2018-08-23 00:56:19 +02:00
|
|
|
import gdsMill
|
|
|
|
|
import tech
|
|
|
|
|
from contact import contact
|
|
|
|
|
import math
|
|
|
|
|
import debug
|
|
|
|
|
import grid
|
|
|
|
|
from pin_layout import pin_layout
|
|
|
|
|
from vector import vector
|
|
|
|
|
from vector3d import vector3d
|
|
|
|
|
from globals import OPTS
|
|
|
|
|
from router import router
|
|
|
|
|
|
|
|
|
|
class supply_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.
|
|
|
|
|
"""
|
|
|
|
|
|
2018-08-30 00:32:45 +02:00
|
|
|
def __init__(self, gds_name=None, module=None):
|
2018-09-06 20:54:14 +02:00
|
|
|
"""
|
|
|
|
|
Use the gds file for the blockages with the top module topName and
|
2018-08-23 00:56:19 +02:00
|
|
|
layers for the layers to route on
|
|
|
|
|
"""
|
2018-08-30 00:32:45 +02:00
|
|
|
router.__init__(self, gds_name, module)
|
2018-09-06 23:30:59 +02:00
|
|
|
|
2018-08-23 00:56:19 +02:00
|
|
|
|
2018-09-06 20:54:14 +02:00
|
|
|
def create_routing_grid(self):
|
|
|
|
|
"""
|
|
|
|
|
Create a sprase routing grid with A* expansion functions.
|
2018-08-23 00:56:19 +02:00
|
|
|
"""
|
2018-09-06 20:54:14 +02:00
|
|
|
size = self.ur - self.ll
|
|
|
|
|
debug.info(1,"Size: {0} x {1}".format(size.x,size.y))
|
2018-08-23 00:56:19 +02:00
|
|
|
|
2018-09-06 20:54:14 +02:00
|
|
|
import supply_grid
|
|
|
|
|
self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width)
|
2018-09-06 01:01:11 +02:00
|
|
|
|
2018-08-23 00:56:19 +02:00
|
|
|
def route(self, cell, layers, vdd_name="vdd", gnd_name="gnd"):
|
|
|
|
|
"""
|
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
|
|
|
"""
|
2018-08-30 00:32:45 +02:00
|
|
|
debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
|
2018-08-23 00:56:19 +02:00
|
|
|
self.cell = cell
|
|
|
|
|
self.pins[vdd_name] = []
|
|
|
|
|
self.pins[gnd_name] = []
|
|
|
|
|
|
|
|
|
|
# Clear the pins if we have previously routed
|
|
|
|
|
if (hasattr(self,'rg')):
|
|
|
|
|
self.clear_pins()
|
|
|
|
|
else:
|
|
|
|
|
# Set up layers and track sizes
|
|
|
|
|
self.set_layers(layers)
|
|
|
|
|
# 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()
|
|
|
|
|
# This will get all shapes as blockages
|
|
|
|
|
self.find_blockages()
|
|
|
|
|
|
|
|
|
|
# Get the pin shapes
|
|
|
|
|
self.get_pin(vdd_name)
|
|
|
|
|
self.get_pin(gnd_name)
|
|
|
|
|
|
2018-09-06 01:01:11 +02:00
|
|
|
# Now add the blockages (all shapes except the pins)
|
2018-08-23 00:56:19 +02:00
|
|
|
self.add_blockages()
|
|
|
|
|
|
2018-09-06 20:54:14 +02:00
|
|
|
self.route_supply_rails()
|
2018-09-06 01:01:11 +02:00
|
|
|
|
|
|
|
|
#self.route_supply_pins()
|
|
|
|
|
|
2018-08-28 19:41:19 +02:00
|
|
|
# source pin will be a specific layout pin
|
|
|
|
|
# target pin will be the rails only
|
2018-08-23 00:56:19 +02:00
|
|
|
|
|
|
|
|
# returns the path in tracks
|
2018-08-28 19:41:19 +02:00
|
|
|
# (path,cost) = self.rg.route(detour_scale)
|
|
|
|
|
# if path:
|
|
|
|
|
# debug.info(1,"Found path: cost={0} ".format(cost))
|
|
|
|
|
# debug.info(2,str(path))
|
|
|
|
|
# self.add_route(path)
|
|
|
|
|
# return True
|
|
|
|
|
# else:
|
|
|
|
|
# self.write_debug_gds()
|
|
|
|
|
# # clean up so we can try a reroute
|
|
|
|
|
# self.clear_pins()
|
2018-08-23 00:56:19 +02:00
|
|
|
|
2018-08-28 19:41:19 +02:00
|
|
|
self.write_debug_gds()
|
2018-08-23 00:56:19 +02:00
|
|
|
return False
|
|
|
|
|
|
2018-09-06 01:01:11 +02:00
|
|
|
def route_supply_rails(self):
|
|
|
|
|
"""
|
|
|
|
|
Add supply rails for vdd and gnd alternating in both layers.
|
|
|
|
|
Connect cross-over points with vias.
|
|
|
|
|
"""
|
2018-09-06 23:30:59 +02:00
|
|
|
# width in grid units
|
|
|
|
|
width = 2
|
|
|
|
|
|
|
|
|
|
# List of all the rails
|
|
|
|
|
self.rails = []
|
|
|
|
|
self.wave_paths = []
|
|
|
|
|
|
|
|
|
|
# vdd will be the even grids every 2 widths
|
|
|
|
|
for offset in range(0, self.rg.ur.y, 2*width):
|
|
|
|
|
loc = vector3d(0,offset,0)
|
|
|
|
|
# While we can keep expanding east
|
|
|
|
|
while loc and loc.x < self.rg.ur.x:
|
|
|
|
|
loc = self.route_horizontal_supply_rail("vdd",loc,width)
|
2018-09-06 01:01:11 +02:00
|
|
|
|
2018-09-06 23:30:59 +02:00
|
|
|
# gnd will be the odd grids every 2 widths
|
|
|
|
|
for offset in range(width, self.rg.ur.y, 2*width):
|
|
|
|
|
loc = vector3d(0,offset,0)
|
|
|
|
|
# While we can keep expanding east
|
|
|
|
|
while loc and loc.x < self.rg.ur.x:
|
|
|
|
|
loc = self.route_horizontal_supply_rail("gnd",loc,width)
|
|
|
|
|
|
|
|
|
|
# vdd will be the even grids every 2 widths
|
|
|
|
|
for offset in range(0, self.rg.ur.x, 2*width):
|
|
|
|
|
loc = vector3d(offset,0,0)
|
|
|
|
|
# While we can keep expanding up
|
|
|
|
|
while loc and loc.y < self.rg.ur.y:
|
|
|
|
|
loc = self.route_vertical_supply_rail("vdd",loc,width)
|
|
|
|
|
|
|
|
|
|
# gnd will be the odd grids every 2 widths
|
|
|
|
|
for offset in range(width, self.rg.ur.x, 2*width):
|
|
|
|
|
loc = vector3d(offset,0,0)
|
|
|
|
|
# While we can keep expanding up
|
|
|
|
|
while loc and loc.y < self.rg.ur.y:
|
|
|
|
|
loc = self.route_vertical_supply_rail("gnd",loc,width)
|
|
|
|
|
|
2018-09-06 01:01:11 +02:00
|
|
|
|
|
|
|
|
|
2018-09-06 23:30:59 +02:00
|
|
|
def route_horizontal_supply_rail(self, name, loc, width):
|
2018-09-06 20:54:14 +02:00
|
|
|
"""
|
|
|
|
|
Add supply rails alternating layers.
|
2018-09-06 23:30:59 +02:00
|
|
|
Return the final wavefront for seeding the next wave.
|
2018-09-06 20:54:14 +02:00
|
|
|
"""
|
2018-09-06 23:30:59 +02:00
|
|
|
# Sweep to find an initial wave
|
|
|
|
|
start_wave = self.rg.find_horizontal_start_wave(loc, width)
|
|
|
|
|
if not start_wave:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
# Expand the wave to the right
|
|
|
|
|
wave_path = self.rg.probe_east_wave(start_wave)
|
|
|
|
|
if not wave_path:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
# Filter single unit paths
|
|
|
|
|
# FIXME: Should we filter bigger sizes?
|
|
|
|
|
if len(wave_path)>1:
|
|
|
|
|
new_pin = self.add_wave(name, wave_path)
|
|
|
|
|
self.rails.append(new_pin)
|
|
|
|
|
self.wave_paths.append(wave_path)
|
|
|
|
|
|
|
|
|
|
# seed the next start wave location
|
|
|
|
|
wave_end = wave_path[-1]
|
|
|
|
|
next_seed = wave_end[0]+vector3d(1,0,0)
|
|
|
|
|
return next_seed
|
|
|
|
|
|
|
|
|
|
def route_vertical_supply_rail(self, name, loc, width):
|
|
|
|
|
"""
|
|
|
|
|
Add supply rails alternating layers.
|
|
|
|
|
Return the final wavefront for seeding the next wave.
|
|
|
|
|
"""
|
|
|
|
|
# Sweep to find an initial wave
|
|
|
|
|
start_wave = self.rg.find_vertical_start_wave(loc, width)
|
|
|
|
|
if not start_wave:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
# Expand the wave to the right
|
|
|
|
|
wave_path = self.rg.probe_up_wave(start_wave)
|
|
|
|
|
if not wave_path:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
# Filter single unit paths
|
|
|
|
|
# FIXME: Should we filter bigger sizes?
|
|
|
|
|
if len(wave_path)>1:
|
|
|
|
|
new_pin = self.add_wave(name, wave_path)
|
|
|
|
|
self.rails.append(new_pin)
|
|
|
|
|
self.wave_paths.append(wave_path)
|
|
|
|
|
|
|
|
|
|
# seed the next start wave location
|
|
|
|
|
wave_end = wave_path[-1]
|
|
|
|
|
next_seed = wave_end[0]+vector3d(0,1,0)
|
|
|
|
|
return next_seed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-09-06 20:54:14 +02:00
|
|
|
|
2018-09-06 01:01:11 +02:00
|
|
|
def route_supply_pins(self, pin):
|
|
|
|
|
"""
|
|
|
|
|
This will route all the supply pins to supply rails one at a time.
|
|
|
|
|
After each one, it adds the cells to the blockage list.
|
|
|
|
|
"""
|
|
|
|
|
for pin_name in self.pins.keys():
|
|
|
|
|
for pin in self.pins[pin_name]:
|
|
|
|
|
route_supply_pin(pin)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def route_supply_pin(self, pin):
|
|
|
|
|
"""
|
|
|
|
|
This will take a single pin and route it to the appropriate supply rail.
|
|
|
|
|
Do not allow other pins to be destinations so that everything is connected
|
|
|
|
|
to the rails.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2018-09-06 23:30:59 +02:00
|
|
|
# def add_route(self,path):
|
|
|
|
|
# """
|
|
|
|
|
# Add the current wire route to the given design instance.
|
|
|
|
|
# """
|
|
|
|
|
# debug.info(3,"Set path: " + str(path))
|
|
|
|
|
|
|
|
|
|
# # Keep track of path for future blockages
|
|
|
|
|
# self.paths.append(path)
|
2018-08-23 00:56:19 +02:00
|
|
|
|
2018-09-06 23:30:59 +02:00
|
|
|
# # This is marked for debug
|
|
|
|
|
# self.rg.add_path(path)
|
|
|
|
|
|
|
|
|
|
# # For debugging... if the path failed to route.
|
|
|
|
|
# if False or path==None:
|
|
|
|
|
# self.write_debug_gds()
|
|
|
|
|
|
|
|
|
|
# # First, simplify the path for
|
|
|
|
|
# #debug.info(1,str(self.path))
|
|
|
|
|
# contracted_path = self.contract_path(path)
|
|
|
|
|
# debug.info(1,str(contracted_path))
|
|
|
|
|
|
|
|
|
|
# # convert the path back to absolute units from tracks
|
|
|
|
|
# abs_path = map(self.convert_point_to_units,contracted_path)
|
|
|
|
|
# debug.info(1,str(abs_path))
|
|
|
|
|
# self.cell.add_route(self.layers,abs_path)
|
2018-08-23 00:56:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|