OpenRAM/compiler/router/grid.py

216 lines
7.3 KiB
Python
Raw Normal View History

# 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.
#
2022-11-27 22:01:20 +01:00
from openram import debug
from openram.base.vector3d import vector3d
from .grid_cell import grid_cell
class grid:
"""
A two layer routing map. Each cell can be blocked in the vertical
or horizontal layer.
"""
# 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)
2020-11-03 15:29:17 +01:00
VIA_COST = 2
NONPREFERRED_COST = 4
PREFERRED_COST = 1
def __init__(self, ll, ur, track_width):
""" Initialize the map and define the costs. """
# list of the source/target grid coordinates
self.source = set()
self.target = set()
self.track_width = track_width
2020-11-03 15:29:17 +01:00
self.track_widths = [self.track_width, self.track_width, 1.0]
self.track_factor = [1 / self.track_width, 1 / self.track_width, 1.0]
2020-11-03 15:29:17 +01:00
# 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()
2021-01-15 22:25:57 +01:00
self.ur = vector3d(ur.x, ur.y, 0).scale(self.track_factor).round()
debug.info(1, "BBOX coords: ll=" + str(ll) + " ur=" + str(ur))
debug.info(1, "BBOX grids: ll=" + str(self.ll) + " ur=" + str(self.ur))
2020-11-03 15:29:17 +01:00
# 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 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))
2020-11-03 15:29:17 +01:00
def set_blocked(self, n, value=True):
2019-05-31 17:43:37 +02:00
if not isinstance(n, vector3d):
for item in n:
self.set_blocked(item, value)
else:
self.add_map(n)
self.map[n].blocked=value
def is_blocked(self, n):
2019-05-31 17:43:37 +02:00
if not isinstance(n, vector3d):
for item in n:
if self.is_blocked(item):
return True
else:
return False
else:
self.add_map(n)
return self.map[n].blocked
2022-03-18 18:32:25 +01:00
def is_inside(self, n):
if not isinstance(n, vector3d):
for item in n:
if self.is_inside(item):
return True
else:
return False
else:
return n.x >= self.ll.x and n.x <= self.ur.x and n.y >= self.ll.y and n.y <= self.ur.y
def set_path(self, n, value=True):
if isinstance(n, (list, tuple, set, frozenset)):
for item in n:
self.set_path(item, value)
else:
self.add_map(n)
self.map[n].path=value
def clear_blockages(self):
for k in self.map:
self.map[k].blocked=False
2020-11-03 15:29:17 +01:00
def clear_source(self):
for k in self.map:
self.map[k].source=False
self.source = set()
def set_source(self, n):
2019-05-31 17:43:37 +02:00
if not isinstance(n, vector3d):
for item in n:
self.set_source(item)
else:
self.add_map(n)
self.map[n].source=True
self.map[n].blocked=False
self.source.add(n)
2020-11-03 15:29:17 +01:00
def clear_target(self):
for k in self.map:
self.map[k].target=False
self.target = set()
2022-07-22 18:52:38 +02:00
def set_target(self, n):
2019-05-31 17:43:37 +02:00
if not isinstance(n, vector3d):
for item in n:
self.set_target(item)
else:
self.add_map(n)
self.map[n].target=True
self.map[n].blocked=False
self.target.add(n)
2022-07-22 18:52:38 +02:00
def add_source(self, track_list):
debug.info(3, "Adding source list={0}".format(str(track_list)))
for n in track_list:
debug.info(4, "Adding source ={0}".format(str(n)))
self.set_source(n)
# self.set_blocked(n, False)
def add_target(self, track_list):
debug.info(3, "Adding target list={0}".format(str(track_list)))
for n in track_list:
debug.info(4, "Adding target ={0}".format(str(n)))
self.set_target(n)
# self.set_blocked(n, False)
def get_perimeter_list(self, side="left", layers=[0, 1], width=1, margin=0, offset=0):
"""
Side specifies which side.
Layer specifies horizontal (0) or vertical (1)
2022-03-18 18:32:25 +01:00
Width specifies how wide the perimeter "stripe" should be.
Works from the inside out from the bbox (ll, ur)
"""
if "ring" in side:
ring_width = width
else:
ring_width = 0
if "ring" in side:
ring_offset = offset
else:
ring_offset = 0
perimeter_list = []
# Add the left/right columns
if side=="all" or "left" in side:
for x in range(self.ll.x - offset, self.ll.x - width - offset, -1):
for y in range(self.ll.y - ring_offset - margin - ring_width + 1, self.ur.y + ring_offset + margin + ring_width, 1):
for layer in layers:
perimeter_list.append(vector3d(x, y, layer))
2022-07-22 18:52:38 +02:00
if side=="all" or "right" in side:
for x in range(self.ur.x + offset, self.ur.x + width + offset, 1):
for y in range(self.ll.y - ring_offset - margin - ring_width + 1, self.ur.y + ring_offset + margin + ring_width, 1):
for layer in layers:
perimeter_list.append(vector3d(x, y, layer))
if side=="all" or "bottom" in side:
for y in range(self.ll.y - offset, self.ll.y - width - offset, -1):
for x in range(self.ll.x - ring_offset - margin - ring_width + 1, self.ur.x + ring_offset + margin + ring_width, 1):
for layer in layers:
perimeter_list.append(vector3d(x, y, layer))
if side=="all" or "top" in side:
for y in range(self.ur.y + offset, self.ur.y + width + offset, 1):
for x in range(self.ll.x - ring_offset - margin - ring_width + 1, self.ur.x + ring_offset + margin + ring_width, 1):
for layer in layers:
perimeter_list.append(vector3d(x, y, layer))
# Add them all to the map
self.add_map(perimeter_list)
return perimeter_list
2022-07-22 18:52:38 +02:00
def add_perimeter_target(self, side="all", layers=[0, 1]):
debug.info(3, "Adding perimeter target")
2022-07-22 18:52:38 +02:00
perimeter_list = self.get_perimeter_list(side, layers)
2022-07-22 18:52:38 +02:00
self.set_target(perimeter_list)
2022-07-22 18:52:38 +02:00
def is_target(self, point):
"""
Point is in the target set, so we are done.
"""
return point in self.target
2020-11-03 15:29:17 +01:00
def add_map(self, n):
"""
Add a point to the map if it doesn't exist.
"""
2019-05-31 17:43:37 +02:00
if not isinstance(n, vector3d):
for item in n:
self.add_map(item)
else:
if n not in self.map:
self.map[n]=grid_cell()
2020-11-03 15:29:17 +01:00
def block_path(self, path):
2020-11-03 15:29:17 +01:00
"""
Mark the path in the routing grid as blocked.
Also unsets the path flag.
"""
path.set_path(False)
path.set_blocked(True)