blob: 0532574a59db20e685e8d1bd25c7c690241f6798 [file] [log] [blame] [edit]
from data_structs import Loc
from lib.rr_graph import tracks
import lib.rr_graph.graph2 as rr
# =============================================================================
def add_track(graph, track, segment_id, node_timing=None):
"""
Adds a track to the graph. Returns the node object representing the track
node.
"""
if node_timing is None:
node_timing = rr.NodeTiming(r=0.0, c=0.0)
node_id = graph.add_track(track, segment_id, timing=node_timing)
node = graph.nodes[-1]
assert node.id == node_id
return node
def add_node(graph, loc, direction, segment_id):
"""
Adds a track of length 1 to the graph. Returns the node object
"""
return add_track(
graph,
tracks.Track(
direction=direction,
x_low=loc.x,
x_high=loc.x,
y_low=loc.y,
y_high=loc.y,
), segment_id
)
def add_edge(
graph, src_node_id, dst_node_id, switch_id, meta_name=None,
meta_value=""
):
"""
Adds an edge to the routing graph. If the given switch corresponds to a
"pass" type switch then adds two edges going both ways.
"""
# Sanity check
assert src_node_id != dst_node_id, \
(src_node_id, dst_node_id, switch_id, meta_name, meta_value)
# Connect src to dst
graph.add_edge(src_node_id, dst_node_id, switch_id, meta_name, meta_value)
# Check if the switch is of the "pass" type. If so then add an edge going
# in the opposite way.
switch = graph.switch_map[switch_id]
if switch.type in [rr.SwitchType.SHORT, rr.SwitchType.PASS_GATE]:
graph.add_edge(
dst_node_id, src_node_id, switch_id, meta_name, meta_value
)
# =============================================================================
def node_joint_location(node_a, node_b):
"""
Given two VPR nodes returns a location of the point where they touch each
other.
"""
loc_a1 = Loc(node_a.loc.x_low, node_a.loc.y_low, 0)
loc_a2 = Loc(node_a.loc.x_high, node_a.loc.y_high, 0)
loc_b1 = Loc(node_b.loc.x_low, node_b.loc.y_low, 0)
loc_b2 = Loc(node_b.loc.x_high, node_b.loc.y_high, 0)
if loc_a1 == loc_b1:
return loc_a1
if loc_a1 == loc_b2:
return loc_a1
if loc_a2 == loc_b1:
return loc_a2
if loc_a2 == loc_b2:
return loc_a2
assert False, (node_a, node_b)
def connect(
graph,
src_node,
dst_node,
switch_id=None,
segment_id=None,
meta_name=None,
meta_value=""
):
"""
Connect two VPR nodes in a way that certain rules are obeyed.
The rules are:
- a CHANX cannot connect directly to a CHANY and vice versa,
- a CHANX cannot connect to an IPIN facing left or right,
- a CHANY cannot connect to an IPIN facting top or bottom,
- an OPIN facing left or right cannot connect to a CHANX,
- an OPIN facing top or bottom cannot connect to a CHANY
Whenever a rule is not met then the connection is made through a padding
node:
src -> [delayless] -> pad -> [desired switch] -> dst
Otherwise the connection is made directly
src -> [desired switch] -> dst
The influence of whether the rules are obeyed or not on the actual VPR
behavior is unclear.
"""
# Use the default delayless switch if none is given
if switch_id is None:
switch_id = graph.get_delayless_switch_id()
# Determine which segment to use if none given
if segment_id is None:
# If the source is IPIN/OPIN then use the same segment as used by
# the destination.
# If the destination is IPIN/OPIN then do the opposite.
# Finally if both are CHANX/CHANY then use the source's segment.
if src_node.type in [rr.NodeType.IPIN, rr.NodeType.OPIN]:
segment_id = dst_node.segment.segment_id
elif dst_node.type in [rr.NodeType.IPIN, rr.NodeType.OPIN]:
segment_id = src_node.segment.segment_id
else:
segment_id = src_node.segment.segment_id
# CHANX to CHANY or vice-versa
chanx_to_chany = src_node.type == rr.NodeType.CHANX and dst_node.type == rr.NodeType.CHANY
chany_to_chanx = src_node.type == rr.NodeType.CHANY and dst_node.type == rr.NodeType.CHANX
chany_to_chany = src_node.type == rr.NodeType.CHANY and dst_node.type == rr.NodeType.CHANY
chanx_to_chanx = src_node.type == rr.NodeType.CHANX and dst_node.type == rr.NodeType.CHANX
if chany_to_chanx or chanx_to_chany:
# Check loc
node_joint_location(src_node, dst_node)
# Connect directly
add_edge(
graph, src_node.id, dst_node.id, switch_id, meta_name, meta_value
)
# CHANX to CHANX or CHANY to CHANY
elif chany_to_chany or chanx_to_chanx:
loc = node_joint_location(src_node, dst_node)
direction = "X" if src_node.type == rr.NodeType.CHANY else "Y"
# Padding node
pad_node = add_node(graph, loc, direction, segment_id)
# Connect through the padding node
add_edge(
graph, src_node.id, pad_node.id, graph.get_delayless_switch_id()
)
add_edge(
graph, pad_node.id, dst_node.id, switch_id, meta_name, meta_value
)
# OPIN to CHANX/CHANY
elif src_node.type == rr.NodeType.OPIN and dst_node.type in \
[rr.NodeType.CHANX, rr.NodeType.CHANY]:
# All OPINs go right (towards +X)
assert src_node.loc.side == tracks.Direction.RIGHT, src_node
# Connected to CHANX
if dst_node.type == rr.NodeType.CHANX:
loc = node_joint_location(src_node, dst_node)
# Padding node
pad_node = add_node(graph, loc, "Y", segment_id)
# Connect through the padding node
add_edge(
graph, src_node.id, pad_node.id,
graph.get_delayless_switch_id()
)
add_edge(
graph, pad_node.id, dst_node.id, switch_id, meta_name,
meta_value
)
# Connected to CHANY
elif dst_node.type == rr.NodeType.CHANY:
# Directly
add_edge(
graph, src_node.id, dst_node.id, switch_id, meta_name,
meta_value
)
# Should not happen
else:
assert False, dst_node
# CHANX/CHANY to IPIN
elif dst_node.type == rr.NodeType.IPIN and src_node.type in \
[rr.NodeType.CHANX, rr.NodeType.CHANY]:
# All IPINs go top (toward +Y)
assert dst_node.loc.side == tracks.Direction.TOP, dst_node
# Connected to CHANY
if src_node.type == rr.NodeType.CHANY:
loc = node_joint_location(src_node, dst_node)
# Padding node
pad_node = add_node(graph, loc, "X", segment_id)
# Connect through the padding node
add_edge(
graph, src_node.id, pad_node.id,
graph.get_delayless_switch_id()
)
add_edge(
graph, pad_node.id, dst_node.id, switch_id, meta_name,
meta_value
)
# Connected to CHANX
elif src_node.type == rr.NodeType.CHANX:
# Directly
add_edge(
graph, src_node.id, dst_node.id, switch_id, meta_name,
meta_value
)
# Should not happen
else:
assert False, dst_node
# An unhandled case
else:
assert False, (src_node, dst_node)