blob: 43891de9e95e16b24f4171b03f900b8551838a55 [file] [log] [blame]
#include "spatial_route_tree_lookup.h"
#include "globals.h"
SpatialRouteTreeLookup build_route_tree_spatial_lookup(ClusterNetId net, t_rt_node* rt_root) {
constexpr float BIN_AREA_PER_SINK_FACTOR = 4;
auto& device_ctx = g_vpr_ctx.device();
auto& cluster_ctx = g_vpr_ctx.clustering();
auto& route_ctx = g_vpr_ctx.routing();
int fanout = cluster_ctx.clb_nlist.net_sinks(net).size();
t_bb bb = route_ctx.route_bb[net];
float bb_area = (bb.xmax - bb.xmin) * (bb.ymax - bb.ymin);
float bb_area_per_sink = bb_area / fanout;
float bin_area = BIN_AREA_PER_SINK_FACTOR * bb_area_per_sink;
float bin_dim = std::ceil(std::sqrt(bin_area));
size_t bins_x = std::ceil(device_ctx.grid.width() / bin_dim);
size_t bins_y = std::ceil(device_ctx.grid.height() / bin_dim);
SpatialRouteTreeLookup spatial_lookup({bins_x, bins_y});
update_route_tree_spatial_lookup_recur(rt_root, spatial_lookup);
return spatial_lookup;
}
//Adds the sub-tree rooted at rt_node to the spatial look-up
void update_route_tree_spatial_lookup_recur(t_rt_node* rt_node, SpatialRouteTreeLookup& spatial_lookup) {
auto& device_ctx = g_vpr_ctx.device();
auto& rr_node = device_ctx.rr_nodes[rt_node->inode];
int bin_xlow = grid_to_bin_x(rr_node.xlow(), spatial_lookup);
int bin_ylow = grid_to_bin_y(rr_node.ylow(), spatial_lookup);
int bin_xhigh = grid_to_bin_x(rr_node.xhigh(), spatial_lookup);
int bin_yhigh = grid_to_bin_y(rr_node.yhigh(), spatial_lookup);
spatial_lookup[bin_xlow][bin_ylow].push_back(rt_node);
//We current look at the start/end locations of the RR nodes and add the node
//to both bins if they are different
//
//TODO: Depending on bin size, long wires may end up being added only to bins at
// their start/end and may pass through bins along their length to which they
// are not added. If this becomes an issues, reconsider how we add nodes to
// bins
if (bin_xhigh != bin_xlow || bin_yhigh != bin_ylow) {
spatial_lookup[bin_xhigh][bin_yhigh].push_back(rt_node);
}
//Recurse
for (t_linked_rt_edge* rt_edge = rt_node->u.child_list; rt_edge != nullptr; rt_edge = rt_edge->next) {
update_route_tree_spatial_lookup_recur(rt_edge->child, spatial_lookup);
}
}
size_t grid_to_bin_x(size_t grid_x, const SpatialRouteTreeLookup& spatial_lookup) {
auto& device_ctx = g_vpr_ctx.device();
int bin_width = std::ceil(float(device_ctx.grid.width()) / spatial_lookup.dim_size(0));
return grid_x / bin_width;
}
size_t grid_to_bin_y(size_t grid_y, const SpatialRouteTreeLookup& spatial_lookup) {
auto& device_ctx = g_vpr_ctx.device();
int bin_height = std::ceil(float(device_ctx.grid.height()) / spatial_lookup.dim_size(1));
return grid_y / bin_height;
}
bool validate_route_tree_spatial_lookup(t_rt_node* rt_node, const SpatialRouteTreeLookup& spatial_lookup) {
auto& device_ctx = g_vpr_ctx.device();
auto& rr_node = device_ctx.rr_nodes[rt_node->inode];
int bin_xlow = grid_to_bin_x(rr_node.xlow(), spatial_lookup);
int bin_ylow = grid_to_bin_y(rr_node.ylow(), spatial_lookup);
int bin_xhigh = grid_to_bin_x(rr_node.xhigh(), spatial_lookup);
int bin_yhigh = grid_to_bin_y(rr_node.yhigh(), spatial_lookup);
bool valid = true;
auto& low_bin_rt_nodes = spatial_lookup[bin_xlow][bin_ylow];
if (std::find(low_bin_rt_nodes.begin(), low_bin_rt_nodes.end(), rt_node) == low_bin_rt_nodes.end()) {
valid = false;
VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Failed to find route tree node %d at (low coord %d,%d) in spatial lookup [bin %d,%d]",
rt_node->inode, rr_node.xlow(), rr_node.ylow(), bin_xlow, bin_ylow);
}
auto& high_bin_rt_nodes = spatial_lookup[bin_xhigh][bin_yhigh];
if (std::find(high_bin_rt_nodes.begin(), high_bin_rt_nodes.end(), rt_node) == high_bin_rt_nodes.end()) {
valid = false;
VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Failed to find route tree node %d at (high coord %d,%d) in spatial lookup [bin %d,%d]",
rt_node->inode, rr_node.xhigh(), rr_node.yhigh(), bin_xhigh, bin_yhigh);
}
//Recurse
for (t_linked_rt_edge* rt_edge = rt_node->u.child_list; rt_edge != nullptr; rt_edge = rt_edge->next) {
valid &= validate_route_tree_spatial_lookup(rt_edge->child, spatial_lookup);
}
return valid;
}