2019-04-26 21:21:50 +02:00
|
|
|
# See LICENSE for licensing information.
|
|
|
|
|
#
|
2023-01-29 07:56:27 +01:00
|
|
|
# Copyright (c) 2016-2023 Regents of the University of California and The Board
|
2019-06-14 17:43:41 +02:00
|
|
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
|
|
|
# (acting for and on behalf of Oklahoma State University)
|
|
|
|
|
# All rights reserved.
|
2019-04-26 21:21:50 +02:00
|
|
|
#
|
2022-07-13 19:57:56 +02:00
|
|
|
from datetime import datetime
|
2022-11-27 22:01:20 +01:00
|
|
|
from openram import debug
|
|
|
|
|
from openram.base.vector3d import vector3d
|
|
|
|
|
from openram import print_time
|
2022-07-13 19:57:56 +02:00
|
|
|
from .router import router
|
|
|
|
|
from .direction import direction
|
|
|
|
|
from .supply_grid import supply_grid
|
|
|
|
|
from . import grid_utils
|
2018-08-23 00:56:19 +02:00
|
|
|
|
2020-04-23 23:43:54 +02:00
|
|
|
|
2019-05-28 02:38:59 +02:00
|
|
|
class supply_grid_router(router):
|
2018-08-23 00:56:19 +02:00
|
|
|
"""
|
|
|
|
|
A router class to read an obstruction map from a gds and
|
|
|
|
|
routes a grid to connect the supply on the two layers.
|
|
|
|
|
"""
|
|
|
|
|
|
2021-05-28 20:55:50 +02:00
|
|
|
def __init__(self, layers, design, bbox=None, pin_type=None):
|
2018-09-06 20:54:14 +02:00
|
|
|
"""
|
2018-10-04 23:04:29 +02:00
|
|
|
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).
|
2018-08-23 00:56:19 +02:00
|
|
|
"""
|
2020-01-03 12:24:14 +01:00
|
|
|
start_time = datetime.now()
|
|
|
|
|
|
2018-12-04 17:41:57 +01:00
|
|
|
# Power rail width in minimum wire widths
|
2021-05-05 22:45:12 +02:00
|
|
|
self.route_track_width = 1
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2021-05-05 22:45:12 +02:00
|
|
|
router.__init__(self, layers, design, bbox=bbox, margin=margin, route_track_width=self.route_track_width)
|
2018-10-20 23:47:24 +02:00
|
|
|
|
2018-10-20 19:33:10 +02:00
|
|
|
# The list of supply rails (grid sets) that may be routed
|
|
|
|
|
self.supply_rails = {}
|
|
|
|
|
# This is the same as above but as a sigle set for the all the rails
|
2018-10-19 23:21:03 +02:00
|
|
|
self.supply_rail_tracks = {}
|
2018-09-08 19:05:48 +02:00
|
|
|
|
2020-01-03 12:24:14 +01:00
|
|
|
print_time("Init supply router", datetime.now(), start_time, 3)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-04 23:04:29 +02:00
|
|
|
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
2019-11-14 19:17:20 +01:00
|
|
|
"""
|
2018-09-06 01:01:11 +02:00
|
|
|
Add power supply rails and connect all pins to these rails.
|
2018-08-23 00:56:19 +02:00
|
|
|
"""
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(1, "Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
|
2018-09-08 19:05:48 +02:00
|
|
|
self.vdd_name = vdd_name
|
|
|
|
|
self.gnd_name = gnd_name
|
2018-08-23 00:56:19 +02:00
|
|
|
|
|
|
|
|
# Clear the pins if we have previously routed
|
2020-04-23 23:43:54 +02:00
|
|
|
if (hasattr(self, 'rg')):
|
2018-08-23 00:56:19 +02:00
|
|
|
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.
|
2021-01-15 22:25:57 +01:00
|
|
|
self.create_routing_grid(supply_grid)
|
2018-08-23 00:56:19 +02:00
|
|
|
|
|
|
|
|
# Get the pin shapes
|
2018-12-07 22:54:18 +01:00
|
|
|
start_time = datetime.now()
|
2018-10-04 23:04:29 +02:00
|
|
|
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
2020-04-23 23:43:54 +02:00
|
|
|
print_time("Finding pins and blockages", datetime.now(), start_time, 3)
|
2018-09-13 18:10:29 +02:00
|
|
|
# Add the supply rails in a mesh network and connect H/V with vias
|
2018-12-07 22:54:18 +01:00
|
|
|
start_time = datetime.now()
|
2018-09-18 21:57:39 +02:00
|
|
|
# Block everything
|
2021-01-11 20:12:45 +01:00
|
|
|
self.prepare_blockages()
|
|
|
|
|
self.clear_blockages(self.gnd_name)
|
2022-07-22 18:52:38 +02:00
|
|
|
|
|
|
|
|
|
2018-09-18 21:57:39 +02:00
|
|
|
# Determine the rail locations
|
2020-04-23 23:43:54 +02:00
|
|
|
self.route_supply_rails(self.gnd_name, 0)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-09-18 21:57:39 +02:00
|
|
|
# Block everything
|
2021-01-11 20:12:45 +01:00
|
|
|
self.prepare_blockages()
|
2022-07-22 18:52:38 +02:00
|
|
|
self.clear_blockages(self.vdd_name)
|
2018-09-18 21:57:39 +02:00
|
|
|
# Determine the rail locations
|
2020-04-23 23:43:54 +02:00
|
|
|
self.route_supply_rails(self.vdd_name, 1)
|
|
|
|
|
print_time("Routing supply rails", datetime.now(), start_time, 3)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-12-07 22:54:18 +01:00
|
|
|
start_time = datetime.now()
|
2018-10-25 22:36:35 +02:00
|
|
|
self.route_simple_overlaps(vdd_name)
|
|
|
|
|
self.route_simple_overlaps(gnd_name)
|
2020-04-23 23:43:54 +02:00
|
|
|
print_time("Simple overlap routing", datetime.now(), start_time, 3)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-09-13 18:10:29 +02:00
|
|
|
# Route the supply pins to the supply rails
|
2018-10-15 22:58:40 +02:00
|
|
|
# Route vdd first since we want it to be shorter
|
2018-12-07 22:54:18 +01:00
|
|
|
start_time = datetime.now()
|
2018-10-25 22:36:35 +02:00
|
|
|
self.route_pins_to_rails(vdd_name)
|
|
|
|
|
self.route_pins_to_rails(gnd_name)
|
2020-04-23 23:43:54 +02:00
|
|
|
print_time("Maze routing supplies", datetime.now(), start_time, 3)
|
|
|
|
|
# self.write_debug_gds("final.gds", False)
|
2019-04-24 19:54:22 +02:00
|
|
|
|
|
|
|
|
# Did we route everything??
|
|
|
|
|
if not self.check_all_routed(vdd_name):
|
|
|
|
|
return False
|
|
|
|
|
if not self.check_all_routed(gnd_name):
|
|
|
|
|
return False
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-09-18 21:57:39 +02:00
|
|
|
return True
|
2018-08-23 00:56:19 +02:00
|
|
|
|
2018-10-19 23:21:03 +02:00
|
|
|
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.
|
|
|
|
|
"""
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(1, "Routing simple overlap pins for {0}".format(pin_name))
|
2018-11-02 19:11:32 +01:00
|
|
|
|
|
|
|
|
# These are the wire tracks
|
2018-12-04 17:41:57 +01:00
|
|
|
wire_tracks = self.supply_rail_tracks[pin_name]
|
2018-12-06 23:11:15 +01:00
|
|
|
routed_count=0
|
2018-10-25 22:36:35 +02:00
|
|
|
for pg in self.pin_groups[pin_name]:
|
|
|
|
|
if pg.is_routed():
|
|
|
|
|
continue
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-11-02 19:11:32 +01:00
|
|
|
# First, check if we just overlap, if so, we are done.
|
|
|
|
|
overlap_grids = wire_tracks & pg.grids
|
|
|
|
|
if len(overlap_grids)>0:
|
2018-12-06 23:11:15 +01:00
|
|
|
routed_count += 1
|
2018-10-25 22:36:35 +02:00
|
|
|
pg.set_routed()
|
2018-11-02 19:11:32 +01:00
|
|
|
continue
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-12-04 17:41:57 +01:00
|
|
|
# Else, if we overlap some of the space track, we can patch it with an enclosure
|
2020-04-23 23:43:54 +02:00
|
|
|
# pg.create_simple_overlap_enclosure(pg.grids)
|
|
|
|
|
# pg.add_enclosure(self.cell)
|
2018-10-19 23:21:03 +02:00
|
|
|
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(1, "Routed {} simple overlap pins".format(routed_count))
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-20 19:33:10 +02:00
|
|
|
def finalize_supply_rails(self, name):
|
2018-09-07 23:46:58 +02:00
|
|
|
"""
|
2018-09-18 21:57:39 +02:00
|
|
|
Determine which supply rails overlap and can accomodate a via.
|
2018-10-11 00:15:58 +02:00
|
|
|
Remove any supply rails that do not have a via since they are disconnected.
|
|
|
|
|
NOTE: It is still possible though unlikely that there are disconnected groups of rails.
|
2018-09-07 23:46:58 +02:00
|
|
|
"""
|
|
|
|
|
|
2018-12-04 17:41:57 +01:00
|
|
|
all_rails = self.supply_rails[name]
|
2018-10-20 19:33:10 +02:00
|
|
|
|
|
|
|
|
connections = set()
|
|
|
|
|
via_areas = []
|
2020-04-23 23:43:54 +02:00
|
|
|
for i1, r1 in enumerate(all_rails):
|
2018-10-20 23:25:32 +02:00
|
|
|
# Only consider r1 horizontal rails
|
2018-10-20 19:33:10 +02:00
|
|
|
e = next(iter(r1))
|
2018-10-20 23:25:32 +02:00
|
|
|
if e.z==1:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
# We need to move this rail to the other layer for the z indices to match
|
|
|
|
|
# during the intersection. This also makes a copy.
|
2020-04-23 23:43:54 +02:00
|
|
|
new_r1 = {vector3d(i.x, i.y, 1) for i in r1}
|
2019-04-24 19:54:22 +02:00
|
|
|
|
2020-04-23 23:43:54 +02:00
|
|
|
for i2, r2 in enumerate(all_rails):
|
2018-10-20 23:25:32 +02:00
|
|
|
# Never compare to yourself
|
2018-10-20 19:33:10 +02:00
|
|
|
if i1==i2:
|
|
|
|
|
continue
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-20 23:25:32 +02:00
|
|
|
# Only consider r2 vertical rails
|
|
|
|
|
e = next(iter(r2))
|
|
|
|
|
if e.z==0:
|
|
|
|
|
continue
|
|
|
|
|
|
2019-04-23 00:30:35 +02:00
|
|
|
# Determine if we have sufficient overlap and, if so,
|
2018-10-20 23:25:32 +02:00
|
|
|
# remember:
|
|
|
|
|
# the indices to determine a rail is connected to another
|
|
|
|
|
# the overlap area for placement of a via
|
2019-04-23 00:30:35 +02:00
|
|
|
overlap = new_r1 & r2
|
2018-12-04 17:41:57 +01:00
|
|
|
if len(overlap) >= 1:
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(3, "Via overlap {0} {1}".format(len(overlap),overlap))
|
|
|
|
|
connections.update([i1, i2])
|
2018-10-20 19:33:10 +02:00
|
|
|
via_areas.append(overlap)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-09-18 21:57:39 +02:00
|
|
|
# Go through and add the vias at the center of the intersection
|
2018-10-20 19:33:10 +02:00
|
|
|
for area in via_areas:
|
|
|
|
|
ll = grid_utils.get_lower_left(area)
|
|
|
|
|
ur = grid_utils.get_upper_right(area)
|
2020-04-23 23:43:54 +02:00
|
|
|
center = (ll + ur).scale(0.5, 0.5, 0)
|
|
|
|
|
self.add_via(center, 1)
|
2018-09-18 21:57:39 +02:00
|
|
|
|
2018-10-20 23:25:32 +02:00
|
|
|
# Determien which indices were not connected to anything above
|
2018-10-26 18:25:10 +02:00
|
|
|
missing_indices = set([x for x in range(len(self.supply_rails[name]))])
|
|
|
|
|
missing_indices.difference_update(connections)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-20 23:25:32 +02:00
|
|
|
# Go through and remove those disconnected indices
|
|
|
|
|
# (No via was added, so that doesn't need to be removed)
|
2018-10-26 18:25:10 +02:00
|
|
|
for rail_index in sorted(missing_indices, reverse=True):
|
2018-10-20 19:33:10 +02:00
|
|
|
ll = grid_utils.get_lower_left(all_rails[rail_index])
|
|
|
|
|
ur = grid_utils.get_upper_right(all_rails[rail_index])
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(1, "Removing disconnected supply rail {0} .. {1}".format(ll, ur))
|
2018-10-20 19:33:10 +02:00
|
|
|
self.supply_rails[name].pop(rail_index)
|
|
|
|
|
|
2018-10-20 23:25:32 +02:00
|
|
|
# Make the supply rails into a big giant set of grids for easy blockages.
|
|
|
|
|
# Must be done after we determine which ones are connected.
|
2018-10-20 19:33:10 +02:00
|
|
|
self.create_supply_track_set(name)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-09-18 21:57:39 +02:00
|
|
|
def add_supply_rails(self, name):
|
|
|
|
|
"""
|
|
|
|
|
Add the shapes that represent the routed supply rails.
|
|
|
|
|
This is after the paths have been pruned and only include rails that are
|
|
|
|
|
connected with vias.
|
|
|
|
|
"""
|
2018-10-20 19:33:10 +02:00
|
|
|
for rail in self.supply_rails[name]:
|
|
|
|
|
ll = grid_utils.get_lower_left(rail)
|
2020-11-03 15:29:17 +01:00
|
|
|
ur = grid_utils.get_upper_right(rail)
|
2018-10-20 19:33:10 +02:00
|
|
|
z = ll.z
|
2018-12-04 17:41:57 +01:00
|
|
|
pin = self.compute_pin_enclosure(ll, ur, z, name)
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(3, "Adding supply rail {0} {1}->{2} {3}".format(name, ll, ur, pin))
|
2018-10-20 19:33:10 +02:00
|
|
|
self.cell.add_layout_pin(text=name,
|
|
|
|
|
layer=pin.layer,
|
|
|
|
|
offset=pin.ll(),
|
|
|
|
|
width=pin.width(),
|
|
|
|
|
height=pin.height())
|
2018-09-18 21:57:39 +02:00
|
|
|
|
2018-10-15 22:58:40 +02:00
|
|
|
def compute_supply_rails(self, name, supply_number):
|
2018-10-15 20:25:51 +02:00
|
|
|
"""
|
|
|
|
|
Compute the unblocked locations for the horizontal and vertical supply rails.
|
|
|
|
|
Go in a raster order from bottom to the top (for horizontal) and left to right
|
|
|
|
|
(for vertical). Start with an initial start_offset in x and y direction.
|
|
|
|
|
"""
|
2018-10-20 19:33:10 +02:00
|
|
|
|
|
|
|
|
self.supply_rails[name]=[]
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-12-05 18:51:17 +01:00
|
|
|
max_yoffset = self.rg.ur.y
|
|
|
|
|
max_xoffset = self.rg.ur.x
|
|
|
|
|
min_yoffset = self.rg.ll.y
|
|
|
|
|
min_xoffset = self.rg.ll.x
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-09-08 19:05:48 +02:00
|
|
|
# Horizontal supply rails
|
2018-12-06 20:58:19 +01:00
|
|
|
start_offset = min_yoffset + supply_number
|
2018-12-05 18:51:17 +01:00
|
|
|
for offset in range(start_offset, max_yoffset, 2):
|
2018-09-07 23:46:58 +02:00
|
|
|
# Seed the function at the location with the given width
|
2020-04-23 23:43:54 +02:00
|
|
|
wave = [vector3d(min_xoffset, offset, 0)]
|
2018-09-08 19:05:48 +02:00
|
|
|
# While we can keep expanding east in this horizontal track
|
2018-12-05 18:51:17 +01:00
|
|
|
while wave and wave[0].x < max_xoffset:
|
2018-10-20 19:33:10 +02:00
|
|
|
added_rail = self.find_supply_rail(name, wave, direction.EAST)
|
2018-10-24 21:32:27 +02:00
|
|
|
if not added_rail:
|
|
|
|
|
# Just seed with the next one
|
2020-04-23 23:43:54 +02:00
|
|
|
wave = [x+vector3d(1, 0, 0) for x in wave]
|
2018-10-20 19:33:10 +02:00
|
|
|
else:
|
2018-10-24 21:32:27 +02:00
|
|
|
# Seed with the neighbor of the end of the last rail
|
|
|
|
|
wave = added_rail.neighbor(direction.EAST)
|
2018-09-06 23:30:59 +02:00
|
|
|
|
2018-09-08 19:05:48 +02:00
|
|
|
# Vertical supply rails
|
2018-12-06 20:58:19 +01:00
|
|
|
start_offset = min_xoffset + supply_number
|
2018-12-05 18:51:17 +01:00
|
|
|
for offset in range(start_offset, max_xoffset, 2):
|
2018-09-07 23:46:58 +02:00
|
|
|
# Seed the function at the location with the given width
|
2020-04-23 23:43:54 +02:00
|
|
|
wave = [vector3d(offset, min_yoffset, 1)]
|
2018-09-08 19:05:48 +02:00
|
|
|
# While we can keep expanding north in this vertical track
|
2018-12-05 18:51:17 +01:00
|
|
|
while wave and wave[0].y < max_yoffset:
|
2018-10-20 19:33:10 +02:00
|
|
|
added_rail = self.find_supply_rail(name, wave, direction.NORTH)
|
2018-10-24 21:32:27 +02:00
|
|
|
if not added_rail:
|
|
|
|
|
# Just seed with the next one
|
2020-04-23 23:43:54 +02:00
|
|
|
wave = [x + vector3d(0, 1, 0) for x in wave]
|
2018-10-20 19:33:10 +02:00
|
|
|
else:
|
2020-04-23 23:43:54 +02:00
|
|
|
# Seed with the neighbor of the end of the last rail
|
2018-10-24 21:32:27 +02:00
|
|
|
wave = added_rail.neighbor(direction.NORTH)
|
2018-09-06 23:30:59 +02:00
|
|
|
|
2018-09-18 21:57:39 +02:00
|
|
|
def find_supply_rail(self, name, seed_wave, direct):
|
2018-10-20 19:33:10 +02:00
|
|
|
"""
|
|
|
|
|
Find a start location, probe in the direction, and see if the rail is big enough
|
|
|
|
|
to contain a via, and, if so, add it.
|
|
|
|
|
"""
|
2019-04-23 00:30:35 +02:00
|
|
|
# Sweep to find an initial unblocked valid wave
|
|
|
|
|
start_wave = self.rg.find_start_wave(seed_wave, direct)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-24 21:32:27 +02:00
|
|
|
# This means there were no more unblocked grids in the row/col
|
2018-10-20 19:33:10 +02:00
|
|
|
if not start_wave:
|
|
|
|
|
return None
|
2018-10-24 21:32:27 +02:00
|
|
|
|
2018-10-20 19:33:10 +02:00
|
|
|
wave_path = self.probe_supply_rail(name, start_wave, direct)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-24 21:32:27 +02:00
|
|
|
self.approve_supply_rail(name, wave_path)
|
|
|
|
|
|
|
|
|
|
# Return the rail whether we approved it or not,
|
|
|
|
|
# as it will be used to find the next start location
|
|
|
|
|
return wave_path
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-20 19:33:10 +02:00
|
|
|
def probe_supply_rail(self, name, start_wave, direct):
|
|
|
|
|
"""
|
|
|
|
|
This finds the first valid starting location and routes a supply rail
|
|
|
|
|
in the given direction.
|
|
|
|
|
It returns the space after the end of the rail to seed another call for multiple
|
|
|
|
|
supply rails in the same "track" when there is a blockage.
|
|
|
|
|
"""
|
2018-09-06 23:30:59 +02:00
|
|
|
|
|
|
|
|
# Expand the wave to the right
|
2018-09-07 23:46:58 +02:00
|
|
|
wave_path = self.rg.probe(start_wave, direct)
|
2018-10-20 19:33:10 +02:00
|
|
|
|
2018-09-06 23:30:59 +02:00
|
|
|
if not wave_path:
|
|
|
|
|
return None
|
|
|
|
|
|
2018-10-20 19:33:10 +02:00
|
|
|
# drop the first and last steps to leave escape routing room
|
|
|
|
|
# around the blockage that stopped the probe
|
|
|
|
|
# except, don't drop the first if it is the first in a row/column
|
|
|
|
|
if (direct==direction.NORTH and start_wave[0].y>0):
|
|
|
|
|
wave_path.trim_first()
|
|
|
|
|
elif (direct == direction.EAST and start_wave[0].x>0):
|
|
|
|
|
wave_path.trim_first()
|
|
|
|
|
|
|
|
|
|
wave_path.trim_last()
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-20 19:33:10 +02:00
|
|
|
return wave_path
|
|
|
|
|
|
|
|
|
|
def approve_supply_rail(self, name, wave_path):
|
|
|
|
|
"""
|
|
|
|
|
Check if the supply rail is sufficient (big enough) and add it to the
|
|
|
|
|
data structure. Return whether it was added or not.
|
|
|
|
|
"""
|
2018-10-11 00:15:58 +02:00
|
|
|
# We must have at least 2 tracks to drop plus 2 tracks for a via
|
2020-12-21 22:51:50 +01:00
|
|
|
if len(wave_path) >= 4 * self.route_track_width:
|
2018-10-20 19:33:10 +02:00
|
|
|
grid_set = wave_path.get_grids()
|
|
|
|
|
self.supply_rails[name].append(grid_set)
|
|
|
|
|
return True
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-20 19:33:10 +02:00
|
|
|
return False
|
2018-09-06 23:30:59 +02:00
|
|
|
|
2018-10-15 20:25:51 +02:00
|
|
|
def route_supply_rails(self, name, supply_number):
|
|
|
|
|
"""
|
|
|
|
|
Route the horizontal and vertical supply rails across the entire design.
|
|
|
|
|
Must be done with lower left at 0,0
|
|
|
|
|
"""
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(1, "Routing supply rail {0}.".format(name))
|
2018-10-15 20:25:51 +02:00
|
|
|
|
|
|
|
|
# Compute the grid locations of the supply rails
|
2018-10-15 22:58:40 +02:00
|
|
|
self.compute_supply_rails(name, supply_number)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-15 20:25:51 +02:00
|
|
|
# Add the supply rail vias (and prune disconnected rails)
|
2018-10-20 19:33:10 +02:00
|
|
|
self.finalize_supply_rails(name)
|
|
|
|
|
|
2018-10-15 20:25:51 +02:00
|
|
|
# Add the rails themselves
|
|
|
|
|
self.add_supply_rails(name)
|
|
|
|
|
|
2018-10-19 23:21:03 +02:00
|
|
|
def create_supply_track_set(self, pin_name):
|
|
|
|
|
"""
|
2018-10-20 19:33:10 +02:00
|
|
|
Make a single set of all the tracks for the rail and wire itself.
|
2018-10-19 23:21:03 +02:00
|
|
|
"""
|
|
|
|
|
rail_set = set()
|
2018-10-20 19:33:10 +02:00
|
|
|
for rail in self.supply_rails[pin_name]:
|
|
|
|
|
rail_set.update(rail)
|
2018-10-19 23:21:03 +02:00
|
|
|
self.supply_rail_tracks[pin_name] = rail_set
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-25 22:36:35 +02:00
|
|
|
def route_pins_to_rails(self, pin_name):
|
2018-09-08 19:05:48 +02:00
|
|
|
"""
|
2020-04-23 23:43:54 +02:00
|
|
|
This will route each of the remaining pin components to the supply rails.
|
2018-09-08 19:05:48 +02:00
|
|
|
After it is done, the cells are added to the pin blockage list.
|
|
|
|
|
"""
|
2018-09-09 03:55:36 +02:00
|
|
|
|
2018-10-25 22:36:35 +02:00
|
|
|
remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(1, "Maze routing {0} with {1} pin components to connect.".format(pin_name,
|
|
|
|
|
remaining_components))
|
2018-10-05 17:39:28 +02:00
|
|
|
|
2020-04-23 23:43:54 +02:00
|
|
|
for index, pg in enumerate(self.pin_groups[pin_name]):
|
2018-10-25 22:36:35 +02:00
|
|
|
if pg.is_routed():
|
|
|
|
|
continue
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(3, "Routing component {0} {1}".format(pin_name, index))
|
2018-10-25 22:36:35 +02:00
|
|
|
|
|
|
|
|
# Clear everything in the routing grid.
|
2018-09-13 18:10:29 +02:00
|
|
|
self.rg.reinit()
|
2018-10-25 22:36:35 +02:00
|
|
|
|
|
|
|
|
# This is inefficient since it is non-incremental, but it was
|
|
|
|
|
# easier to debug.
|
2021-05-05 22:45:12 +02:00
|
|
|
self.prepare_blockages()
|
|
|
|
|
self.clear_blockages(self.vdd_name)
|
2022-07-22 18:52:38 +02:00
|
|
|
|
2018-09-09 03:55:36 +02:00
|
|
|
# Add the single component of the pin as the source
|
|
|
|
|
# which unmarks it as a blockage too
|
2019-05-28 02:38:59 +02:00
|
|
|
self.add_pin_component_source(pin_name, index)
|
2018-09-13 18:10:29 +02:00
|
|
|
|
2018-09-08 19:05:48 +02:00
|
|
|
# Add all of the rails as targets
|
2018-09-09 03:55:36 +02:00
|
|
|
# Don't add the other pins, but we could?
|
2018-09-08 19:05:48 +02:00
|
|
|
self.add_supply_rail_target(pin_name)
|
2018-10-05 17:39:28 +02:00
|
|
|
|
2018-09-09 03:55:36 +02:00
|
|
|
# Actually run the A* router
|
2018-09-21 01:00:13 +02:00
|
|
|
if not self.run_router(detour_scale=5):
|
2021-05-05 22:45:12 +02:00
|
|
|
self.write_debug_gds("debug_route.gds")
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2020-04-23 23:43:54 +02:00
|
|
|
# if index==3 and pin_name=="vdd":
|
|
|
|
|
# self.write_debug_gds("route.gds",False)
|
2018-09-09 03:55:36 +02:00
|
|
|
|
2018-10-12 23:37:51 +02:00
|
|
|
def add_supply_rail_target(self, pin_name):
|
|
|
|
|
"""
|
|
|
|
|
Add the supply rails of given name as a routing target.
|
|
|
|
|
"""
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(4, "Add supply rail target {}".format(pin_name))
|
2018-10-20 19:33:10 +02:00
|
|
|
# Add the wire itself as the target
|
2018-12-04 17:41:57 +01:00
|
|
|
self.rg.set_target(self.supply_rail_tracks[pin_name])
|
2018-10-20 19:33:10 +02:00
|
|
|
# But unblock all the rail tracks including the space
|
2020-04-23 23:43:54 +02:00
|
|
|
self.rg.set_blocked(self.supply_rail_tracks[pin_name], False)
|
2020-11-03 15:29:17 +01:00
|
|
|
|
2018-10-12 23:37:51 +02:00
|
|
|
def set_supply_rail_blocked(self, value=True):
|
|
|
|
|
"""
|
|
|
|
|
Add the supply rails of given name as a routing target.
|
|
|
|
|
"""
|
2020-04-23 23:43:54 +02:00
|
|
|
debug.info(4, "Blocking supply rail")
|
2018-10-20 19:33:10 +02:00
|
|
|
for rail_name in self.supply_rail_tracks:
|
|
|
|
|
self.rg.set_blocked(self.supply_rail_tracks[rail_name])
|