OpenRAM/compiler/router/grid.py

174 lines
5.1 KiB
Python
Raw Normal View History

import numpy as np
import string
from itertools import tee
import debug
2016-11-17 01:47:31 +01:00
from vector3d import vector3d
from cell import cell
import os
class grid:
"""
A two layer routing map. Each cell can be blocked in the vertical
or horizontal layer.
"""
def __init__(self, ll, ur, track_width):
""" Initialize the map and define the costs. """
# costs are relative to a unit grid
# non-preferred cost allows an off-direction jog of 1 grid
# rather than 2 vias + preferred direction (cost 5)
self.VIA_COST = 2
self.NONPREFERRED_COST = 4
self.PREFERRED_COST = 1
# list of the source/target grid coordinates
self.source = []
self.target = []
self.track_width = track_width
self.track_widths = [self.track_width, self.track_width, 1.0]
self.track_factor = [1/self.track_width, 1/self.track_width, 1.0]
# The bounds are in grids for this
# This is really lower left bottom layer and upper right top layer in 3D.
self.ll = vector3d(ll.x,ll.y,0).scale(self.track_factor).round()
self.ur = vector3d(ur.x,ur.y,1).scale(self.track_factor).round()
# let's leave the map sparse, cells are created on demand to reduce memory
2017-04-14 22:56:09 +02:00
self.map={}
2016-11-17 01:47:31 +01:00
def set_blocked(self,n,value=True):
if isinstance(n,list):
for item in n:
self.set_blocked(item,value)
else:
self.add_map(n)
self.map[n].blocked=value
def is_blocked(self,n):
self.add_map(n)
return self.map[n].blocked
def set_path(self,n,value=True):
if isinstance(n,list):
for item in n:
self.set_path(item,value)
else:
self.add_map(n)
self.map[n].path=value
def add_blockage_shape(self,ll,ur,z):
debug.info(3,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
block_list = []
for x in range(int(ll[0]),int(ur[0])+1):
for y in range(int(ll[1]),int(ur[1])+1):
block_list.append(vector3d(x,y,z))
self.add_blockage(block_list)
def add_blockage(self,block_list):
debug.info(2,"Adding blockage list={0}".format(str(block_list)))
for n in block_list:
self.set_blocked(n)
def set_source(self,n):
if isinstance(n,list):
for item in n:
self.set_source(item)
else:
self.add_map(n)
self.map[n].source=True
self.source.append(n)
def set_target(self,n):
if isinstance(n,list):
for item in n:
self.set_target(item)
else:
self.add_map(n)
self.map[n].target=True
self.target.append(n)
def add_source(self,track_list):
debug.info(2,"Adding source list={0}".format(str(track_list)))
for n in track_list:
debug.info(3,"Adding source ={0}".format(str(n)))
self.set_source(n)
def add_target(self,track_list):
debug.info(2,"Adding target list={0}".format(str(track_list)))
for n in track_list:
debug.info(3,"Adding target ={0}".format(str(n)))
self.set_target(n)
def is_target(self,point):
"""
Point is in the target set, so we are done.
"""
return point in self.target
def add_map(self,n):
"""
Add a point to the map if it doesn't exist.
"""
if isinstance(n,list):
for item in n:
self.add_map(item)
else:
if n not in self.map.keys():
self.map[n]=cell()
2016-11-17 01:47:31 +01:00
def add_path(self,path):
"""
Mark the path in the routing grid for visualization
2016-11-17 01:47:31 +01:00
"""
self.path=path
for p in path:
self.set_path(p)
def block_path(self,path):
"""
Mark the path in the routing grid as blocked.
Also unsets the path flag.
"""
for p in path:
self.set_path(p,False)
self.set_blocked(p)
def cost(self,path):
"""
The cost of the path is the length plus a penalty for the number
of vias. We assume that non-preferred direction is penalized.
"""
# Ignore the source pin layer change, FIXME?
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
plist = pairwise(path)
cost = 0
for p0,p1 in plist:
if p0.z != p1.z: # via
2017-04-14 22:56:09 +02:00
cost += self.VIA_COST
elif p0.x != p1.x: # horizontal
cost += self.NONPREFERRED_COST if (p0.z == 1) else self.PREFERRED_COST
elif p0.y != p1.y: # vertical
cost += self.NONPREFERRED_COST if (p0.z == 0) else self.PREFERRED_COST
else:
debug.error("Non-changing direction!")
return cost