many bug fixing and now start improving the routability of tileable rr_graph

This commit is contained in:
tangxifan 2019-06-24 17:33:29 -06:00
parent 0d62661c71
commit fd301eeb66
10 changed files with 234 additions and 49 deletions

View File

@ -302,3 +302,23 @@ DeviceCoordinator get_track_rr_node_end_coordinator(const t_rr_node* track_rr_no
return start_coordinator;
}
/************************************************************************
* Get the ptc of a routing track in the channel where it ends
* For routing tracks in INC_DIRECTION
* the ptc is the last of track_ids
*
* For routing tracks in DEC_DIRECTION
* the ptc is the first of track_ids
***********************************************************************/
short get_track_rr_node_end_track_id(const t_rr_node* track_rr_node) {
/* Make sure we have CHANX or CHANY */
assert ( (CHANX == track_rr_node->type) ||(CHANY == track_rr_node->type) );
if (INC_DIRECTION == track_rr_node->direction) {
return track_rr_node->track_ids.back();
}
assert (DEC_DIRECTION == track_rr_node->direction);
return track_rr_node->track_ids.front();
}

View File

@ -34,5 +34,7 @@ DeviceCoordinator get_track_rr_node_start_coordinator(const t_rr_node* track_rr_
DeviceCoordinator get_track_rr_node_end_coordinator(const t_rr_node* track_rr_node);
short get_track_rr_node_end_track_id(const t_rr_node* track_rr_node);
#endif

View File

@ -191,7 +191,7 @@ ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const si
}
/* Find the number of segments required by each group */
std::vector<size_t> num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, TRUE);
std::vector<size_t> num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, FALSE);
/* Add node to ChanNodeDetails */
size_t cur_track = 0;
@ -208,8 +208,9 @@ ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const si
if (0 == itrack % seg_len) {
seg_start = true;
}
/* Every last track of a group of Length-N wires, we set an ending point */
if (seg_len - 1 == itrack % seg_len) {
/* Every last track of a group of Length-N wires or this is the last track in this group, we set an ending point */
if ( (seg_len - 1 == itrack % seg_len)
|| (itrack == num_tracks[iseg] - 1) ) {
seg_end = true;
}
/* Since this is a unidirectional routing architecture,

View File

@ -869,6 +869,75 @@ void clear_rr_graph_driver_switch(const t_rr_graph* rr_graph) {
return;
}
/************************************************************************
* Sort the edges of rr_nodes by node type and ptc_num
* 1. node type priority: (follow the index of t_rr_type
* SOURCE, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES
* 2. node ptc_num (feature number): from low to high
* The ptc_num only matters when two nodes have the same type
***********************************************************************/
static
void sort_rr_graph_edges(t_rr_graph* rr_graph) {
for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) {
/* Create a copy of the edges and switches of this node */
std::vector<int> sorted_edges;
std::vector<short> sorted_switches;
/* Ensure a clean start */
sorted_edges.clear();
sorted_switches.clear();
/* Build the vectors w.r.t. to the order of node_type and ptc_num */
for (int iedge = 0; iedge < rr_graph->rr_node[inode].num_edges; ++iedge) {
/* For blank edges: directly push_back */
if (0 == sorted_edges.size()) {
sorted_edges.push_back(rr_graph->rr_node[inode].edges[iedge]);
sorted_switches.push_back(rr_graph->rr_node[inode].switches[iedge]);
continue;
}
/* Start sorting since the edges are not empty */
size_t insert_pos = sorted_edges.size(); /* the pos to insert. By default, it is the last element */
size_t i_to_node = rr_graph->rr_node[inode].edges[iedge]; /* node_id of the edge connects to */
for (size_t jedge = 0; jedge < sorted_edges.size(); ++jedge) {
size_t j_to_node = sorted_edges[jedge];
/* Sort by node_type and ptc_num */
if (rr_graph->rr_node[i_to_node].type < rr_graph->rr_node[j_to_node].type) {
/* iedge should be ahead of jedge */
insert_pos = jedge;
break; /* least type should stay in the front of the vector */
} else if (rr_graph->rr_node[i_to_node].type == rr_graph->rr_node[j_to_node].type) {
/* Special as track_ids vary, we consider the last track_ids for those node has the same type as inode */
if (rr_graph->rr_node[i_to_node].type == rr_graph->rr_node[inode].type) {
if (get_track_rr_node_end_track_id(&(rr_graph->rr_node[i_to_node]))
< get_track_rr_node_end_track_id(&(rr_graph->rr_node[j_to_node])) ) {
insert_pos = jedge;
break; /* least type should stay in the front of the vector */
}
} else if (rr_graph->rr_node[i_to_node].ptc_num < rr_graph->rr_node[j_to_node].ptc_num) {
/* Now a lower ptc_num will win */
insert_pos = jedge;
break; /* least type should stay in the front of the vector */
}
}
}
/* We find the position, inserted to the vector */
sorted_edges.insert(sorted_edges.begin() + insert_pos, i_to_node);
sorted_switches.insert(sorted_switches.begin() + insert_pos, rr_graph->rr_node[inode].switches[iedge]);
}
/* Overwrite the edges and switches with sorted numbers */
for (size_t iedge = 0; iedge < sorted_edges.size(); ++iedge) {
rr_graph->rr_node[inode].edges[iedge] = sorted_edges[iedge];
}
for (size_t iedge = 0; iedge < sorted_switches.size(); ++iedge) {
rr_graph->rr_node[inode].switches[iedge] = sorted_switches[iedge];
}
}
return;
}
/************************************************************************
* Main function of this file
* Builder for a detailed uni-directional tileable rr_graph
@ -1019,7 +1088,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
}
/************************************************************************
* 6. Build the connections tile by tile:
* 6.1 Build the connections tile by tile:
* We classify rr_nodes into a general switch block (GSB) data structure
* where we create edges to each rr_nodes in the GSB with respect to
* Fc_in and Fc_out, switch block patterns
@ -1032,7 +1101,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
sb_type, Fs);
/************************************************************************
* 7. Build direction connection lists
* 6.2 Build direction connection lists
***********************************************************************/
/* Create data structure of direct-connections */
t_clb_to_clb_directs* clb_to_clb_directs = NULL;
@ -1042,6 +1111,14 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
build_rr_graph_direct_connections(&rr_graph, device_size, grids, delayless_switch,
num_directs, directs, clb_to_clb_directs);
/************************************************************************
* 6.3 Sort the edges of rr_nodes by node type and ptc_num
* During the edge construction, edges are out of orders,
* which are not easy to build tileable routing architecture
* This step can be skipped when you do not use FPGA X2P
***********************************************************************/
sort_rr_graph_edges(&rr_graph);
size_t num_edges = 0;
for (int inode = 0; inode < rr_graph.num_rr_nodes; ++inode) {
num_edges += rr_graph.rr_node[inode].num_edges;
@ -1053,7 +1130,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
clear_rr_graph_driver_switch(&rr_graph);
/************************************************************************
* 8. Allocate external data structures
* 7. Allocate external data structures
* a. cost_index
* b. RC tree
***********************************************************************/
@ -1066,7 +1143,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
wire_to_ipin_switch, base_cost_type);
/************************************************************************
* 9. Sanitizer for the rr_graph, check connectivities of rr_nodes
* 8. Sanitizer for the rr_graph, check connectivities of rr_nodes
***********************************************************************/
/* Print useful information on screen */
@ -1083,7 +1160,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
/************************************************************************
* 10. Free all temp stucts
* 9. Free all temp stucts
***********************************************************************/
/* Free all temp structs */

View File

@ -1109,6 +1109,11 @@ void build_gsb_one_opin_pin2track_map(const t_rr_graph* rr_graph,
actual_track_list.push_back(track_list[inode]);
}
/* Go the next segment if offset is zero or actual_track_list is empty */
if (0 == actual_track_list.size()) {
continue;
}
/* Scale Fc */
int actual_Fc = Fc * actual_track_list.size() / chan_width;
/* Minimum Fc should be 1 : ensure we will drive 1 routing track */
@ -1122,8 +1127,12 @@ void build_gsb_one_opin_pin2track_map(const t_rr_graph* rr_graph,
track_step = std::max(1, (int)track_step);
/* Adapt offset to the range of actual_track_list */
size_t actual_offset = offset % actual_track_list.size();
/* No need to rotate if offset is zero */
if (0 < actual_offset) {
/* rotate the track list by an offset */
std::rotate(actual_track_list.begin(), actual_track_list.begin() + actual_offset, actual_track_list.end());
}
/* Assign tracks */
int track_cnt = 0;
@ -1248,11 +1257,8 @@ t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph,
/* offset counter: it aims to balance the OPIN-to-track for each switch block */
std::vector<size_t> offset;
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
/* Get the chan_side: which is the same as the opin side */
Side side_manager(side);
offset.resize(side_manager.to_size_t());
}
offset.resize(rr_gsb.get_num_sides());
/* Initial offset */
offset.assign(offset.size(), 0);
@ -1275,8 +1281,7 @@ t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph,
int grid_type_index = grids[opin_node->xlow][opin_node->ylow].type->index;
/* Get Fc of the ipin */
int opin_Fc = Fc_out[grid_type_index][opin_node->ptc_num];
/* skip Fc = 0 */
//printf("opin_Fc[%d]=%d\n", opin_node->ptc_num, opin_Fc);
/* skip Fc = 0 or unintialized, those pins are in the <directlist> */
if ( (-1 == opin_Fc)
|| (0 == opin_Fc) ) {
continue;
@ -1286,8 +1291,8 @@ t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph,
/* Give an offset for the first track that this ipin will connect to */
offset[side_manager.to_size_t()],
segment_inf, &opin2track_map);
/* update offset */
offset[side_manager.to_size_t()] += 2;
/* update offset: aim to rotate starting tracks by 1*/
offset[side_manager.to_size_t()] += 1;
}
}

View File

@ -3137,6 +3137,7 @@ void spice_backannotate_vpr_post_route_info(t_det_routing_arch RoutingArch,
/* Build previous node lists for each rr_node */
vpr_printf(TIO_MESSAGE_INFO, "Building previous node list for all Routing Resource Nodes...\n");
build_prev_node_list_rr_nodes(num_rr_nodes, rr_node);
//sort_rr_graph_drive_rr_nodes(num_rr_nodes, rr_node);
/* Build driver switches for each rr_node*/
vpr_printf(TIO_MESSAGE_INFO, "Identifying driver switches for all Routing Resource Nodes...\n");

View File

@ -2528,6 +2528,7 @@ void link_one_pb_graph_node_pin_to_phy_pb_graph_pin(t_pb_graph_pin* cur_pb_graph
}
/* Create the link */
cur_pb_graph_pin->physical_pb_graph_pin = phy_pb_graph_pin;
/*
vpr_printf (TIO_MESSAGE_INFO, " match pin (%s[%d]->%s[%d]) to (%s[%d]->%s[%d]) rotate_offset_acc=%d\n",
cur_pb_graph_pin->parent_node->pb_type->name,
cur_pb_graph_pin->parent_node->placement_index,
@ -2537,6 +2538,7 @@ void link_one_pb_graph_node_pin_to_phy_pb_graph_pin(t_pb_graph_pin* cur_pb_graph
phy_pb_graph_pin->port->name, phy_pb_graph_pin->pin_number,
cur_pb_graph_pin->port->phy_mode_pin_rotate_offset_acc
);
*/
/* Accumulate the phy_mode_pin offset when we have a matched */
if (0 != cur_pb_graph_pin->port->physical_mode_pin_rotate_offset) {
cur_pb_graph_pin->port->phy_mode_pin_rotate_offset_acc += cur_pb_graph_pin->port->physical_mode_pin_rotate_offset;

View File

@ -10,6 +10,7 @@
#include <assert.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>
/* Include vpr structs*/
#include "util.h"
@ -25,6 +26,8 @@
#include "fpga_x2p_pbtypes_utils.h"
#include "fpga_x2p_rr_graph_utils.h"
#include "rr_graph_builder_utils.h"
/* Initial rr_graph */
void init_rr_graph(INOUTP t_rr_graph* local_rr_graph) {
/* Give zero and NULL to all the contents */
@ -985,6 +988,73 @@ void build_prev_node_list_rr_nodes(int LL_num_rr_nodes,
return;
}
/************************************************************************
* Sort the drive_rr_nodes by node type and ptc_num
* 1. node type priority: (follow the index of t_rr_type
* SOURCE, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES
* 2. node ptc_num (feature number): from low to high
* The ptc_num only matters when two nodes have the same type
***********************************************************************/
void sort_rr_graph_drive_rr_nodes(int LL_num_rr_nodes,
t_rr_node* LL_rr_node) {
for (int inode = 0; inode < LL_num_rr_nodes; ++inode) {
/* Create a copy of the edges and switches of this node */
std::vector<t_rr_node*> sorted_drive_nodes;
std::vector<int> sorted_drive_switches;
/* Ensure a clean start */
sorted_drive_nodes.clear();
sorted_drive_switches.clear();
/* Build the vectors w.r.t. to the order of node_type and ptc_num */
for (int i_from_node = 0; i_from_node < LL_rr_node[inode].num_drive_rr_nodes; ++i_from_node) {
/* For blank edges: directly push_back */
if (0 == sorted_drive_nodes.size()) {
sorted_drive_nodes.push_back(LL_rr_node[inode].drive_rr_nodes[i_from_node]);
sorted_drive_switches.push_back(LL_rr_node[inode].drive_switches[i_from_node]);
continue;
}
/* Start sorting since the edges are not empty */
size_t insert_pos = sorted_drive_nodes.size(); /* the pos to insert. By default, it is the last element */
for (size_t j_from_node = 0; j_from_node < sorted_drive_nodes.size(); ++j_from_node) {
/* Sort by node_type and ptc_num */
if (LL_rr_node[inode].drive_rr_nodes[i_from_node]->type < sorted_drive_nodes[j_from_node]->type) {
/* iedge should be ahead of jedge */
insert_pos = j_from_node;
break; /* least type should stay in the front of the vector */
} else if (LL_rr_node[inode].drive_rr_nodes[i_from_node]->type == sorted_drive_nodes[j_from_node]->type) {
/* Special as track_ids vary, we consider the last track_ids for those node has the same type as inode */
if (LL_rr_node[i_from_node].type == LL_rr_node[inode].type) {
if (get_track_rr_node_end_track_id(&(LL_rr_node[i_from_node]))
< get_track_rr_node_end_track_id(&(LL_rr_node[j_from_node])) ) {
insert_pos = j_from_node;
break; /* least type should stay in the front of the vector */
}
/* Now a lower ptc_num will win */
} else if (LL_rr_node[inode].drive_rr_nodes[i_from_node]->ptc_num < sorted_drive_nodes[j_from_node]->ptc_num) {
insert_pos = j_from_node;
break; /* least type should stay in the front of the vector */
}
}
}
/* We find the position, inserted to the vector */
sorted_drive_nodes.insert(sorted_drive_nodes.begin() + insert_pos, LL_rr_node[inode].drive_rr_nodes[i_from_node]);
sorted_drive_switches.insert(sorted_drive_switches.begin() + insert_pos, LL_rr_node[inode].drive_switches[i_from_node]);
}
/* Overwrite the edges and switches with sorted numbers */
for (size_t iedge = 0; iedge < sorted_drive_nodes.size(); ++iedge) {
LL_rr_node[inode].drive_rr_nodes[iedge] = sorted_drive_nodes[iedge];
}
for (size_t iedge = 0; iedge < sorted_drive_switches.size(); ++iedge) {
LL_rr_node[inode].drive_switches[iedge] = sorted_drive_switches[iedge];
}
}
return;
}
void alloc_and_load_prev_node_list_rr_graph_rr_nodes(t_rr_graph* local_rr_graph) {
build_prev_node_list_rr_nodes(local_rr_graph->num_rr_nodes, local_rr_graph->rr_node);

View File

@ -1,3 +1,5 @@
#ifndef FPGA_X2P_RR_GRAPH_UTILS_H
#define FPGA_X2P_RR_GRAPH_UTILS_H
void init_rr_graph(INOUTP t_rr_graph* local_rr_graph);
@ -89,6 +91,9 @@ void free_rr_graph_traceback(t_rr_graph* local_rr_graph,
void build_prev_node_list_rr_nodes(int LL_num_rr_nodes,
t_rr_node* LL_rr_node);
void sort_rr_graph_drive_rr_nodes(int LL_num_rr_nodes,
t_rr_node* LL_rr_node);
void alloc_and_load_prev_node_list_rr_graph_rr_nodes(t_rr_graph* local_rr_graph);
void backannotate_rr_graph_routing_results_to_net_name(t_rr_graph* local_rr_graph);
@ -106,3 +111,5 @@ void get_chan_rr_node_end_coordinate(t_rr_node* chan_rr_node,
int* x_end, int* y_end);
int get_rr_node_wire_length(t_rr_node* src_rr_node);
#endif

View File

@ -1247,7 +1247,6 @@ RRGSB rotate_rr_switch_block_for_mirror(DeviceCoordinator& device_range,
return rotated_rr_switch_block;
}
/* Build a list of Switch blocks, each of which contains a collection of rr_nodes
* We will maintain a list of unique switch blocks, which will be outputted as a Verilog module
* Each switch block in the FPGA fabric will be an instance of these modules.
@ -1258,22 +1257,23 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir,
t_ivec*** LL_rr_node_indices, int num_segments,
t_rr_indexed_data* LL_rr_indexed_data) {
/* Create an object */
DeviceRRGSB LL_drive_rr_gsb;
DeviceRRGSB LL_device_rr_gsb;
/* Initialize */
DeviceCoordinator sb_range((size_t)nx, (size_t)ny);
DeviceCoordinator reserve_range((size_t)nx + 1, (size_t)ny + 1);
LL_drive_rr_gsb.reserve(reserve_range);
LL_device_rr_gsb.reserve(reserve_range);
/* For each switch block, determine the size of array */
for (size_t ix = 0; ix <= sb_range.get_x(); ++ix) {
for (size_t iy = 0; iy <= sb_range.get_y(); ++iy) {
RRGSB rr_sb = build_rr_gsb(sb_range, ix, iy,
RRGSB rr_gsb = build_rr_gsb(sb_range, ix, iy,
LL_num_rr_nodes, LL_rr_node,
LL_rr_node_indices,
num_segments, LL_rr_indexed_data);
DeviceCoordinator sb_coordinator = rr_sb.get_sb_coordinator();
LL_drive_rr_gsb.add_rr_gsb(sb_coordinator, rr_sb);
/* Add to device_rr_gsb */
DeviceCoordinator sb_coordinator = rr_gsb.get_sb_coordinator();
LL_device_rr_gsb.add_rr_gsb(sb_coordinator, rr_gsb);
}
}
/* Report number of unique mirrors */
@ -1283,7 +1283,7 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir,
if (TRUE == output_sb_xml) {
write_device_rr_gsb_to_xml(sb_xml_dir, LL_drive_rr_gsb);
write_device_rr_gsb_to_xml(sb_xml_dir, LL_device_rr_gsb);
/* Skip rotating mirror searching */
vpr_printf(TIO_MESSAGE_INFO,
@ -1294,36 +1294,36 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir,
/* Build a list of unique modules for each Switch Block */
/* Build a list of unique modules for each side of each Switch Block */
LL_drive_rr_gsb.build_unique_module();
LL_device_rr_gsb.build_unique_module();
vpr_printf(TIO_MESSAGE_INFO,
"Detect %lu routing segments used by switch blocks.\n",
LL_drive_rr_gsb.get_num_segments());
LL_device_rr_gsb.get_num_segments());
/* Report number of unique CB Modules */
vpr_printf(TIO_MESSAGE_INFO,
"Detect %d independent connection blocks from %d X-channel connection blocks.\n",
LL_drive_rr_gsb.get_num_cb_unique_module(CHANX), (nx + 0) * (ny + 1) );
LL_device_rr_gsb.get_num_cb_unique_module(CHANX), (nx + 0) * (ny + 1) );
vpr_printf(TIO_MESSAGE_INFO,
"Detect %d independent connection blocks from %d Y-channel connection blocks.\n",
LL_drive_rr_gsb.get_num_cb_unique_module(CHANY), (nx + 1) * (ny + 0) );
LL_device_rr_gsb.get_num_cb_unique_module(CHANY), (nx + 1) * (ny + 0) );
/* Report number of unique SB modules */
vpr_printf(TIO_MESSAGE_INFO,
"Detect %d independent switch blocks from %d switch blocks.\n",
LL_drive_rr_gsb.get_num_sb_unique_module(), (nx + 1) * (ny + 1) );
LL_device_rr_gsb.get_num_sb_unique_module(), (nx + 1) * (ny + 1) );
/* Report number of unique mirrors */
for (size_t side = 0; side < LL_drive_rr_gsb.get_max_num_sides(); ++side) {
for (size_t side = 0; side < LL_device_rr_gsb.get_max_num_sides(); ++side) {
Side side_manager(side);
/* get segment ids */
for (size_t iseg = 0; iseg < LL_drive_rr_gsb.get_num_segments(); ++iseg) {
for (size_t iseg = 0; iseg < LL_device_rr_gsb.get_num_segments(); ++iseg) {
vpr_printf(TIO_MESSAGE_INFO,
"For side %s, segment id %lu: Detect %d independent switch blocks from %d switch blocks.\n",
side_manager.c_str(), LL_drive_rr_gsb.get_segment_id(iseg),
LL_drive_rr_gsb.get_num_sb_unique_submodule(side_manager.get_side(), iseg),
side_manager.c_str(), LL_device_rr_gsb.get_segment_id(iseg),
LL_device_rr_gsb.get_num_sb_unique_submodule(side_manager.get_side(), iseg),
(nx + 1) * (ny + 1) );
}
}
@ -1335,8 +1335,8 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir,
for (size_t ix = 0; ix <= sb_range.get_x(); ++ix) {
for (size_t iy = 0; iy <= sb_range.get_y(); ++iy) {
RRGSB rr_sb = LL_drive_rr_gsb.get_gsb(ix, iy);
RRGSB rotated_rr_sb = rotate_rr_switch_block_for_mirror(sb_range, rr_sb);
RRGSB rr_gsb = LL_device_rr_gsb.get_gsb(ix, iy);
RRGSB rotated_rr_sb = rotate_rr_switch_block_for_mirror(sb_range, rr_gsb);
if (TRUE == output_sb_xml) {
std::string fname_prefix(sb_xml_dir);
/* Add slash if needed */
@ -1345,12 +1345,12 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir,
//}
//fname_prefix += "rotated_";
//write_rr_switch_block_to_xml(fname_prefix, rotated_rr_sb);
write_rr_switch_block_to_xml(fname_prefix, rr_sb);
write_rr_switch_block_to_xml(fname_prefix, rr_gsb);
}
}
}
return LL_drive_rr_gsb;
return LL_device_rr_gsb;
}