keep developing tileable rr_graph, track2ipin and opin2track to go

This commit is contained in:
tangxifan 2019-06-19 21:30:16 -06:00
parent ba15358564
commit 2f15d2d13c
6 changed files with 771 additions and 269 deletions

View File

@ -56,7 +56,6 @@
#include "ReadOptions.h" #include "ReadOptions.h"
#include "rr_graph.h" #include "rr_graph.h"
#include "rr_graph2.h" #include "rr_graph2.h"
#include "rr_graph_tileable_sbox.h"
#include "route_common.h" #include "route_common.h"
#include "fpga_x2p_types.h" #include "fpga_x2p_types.h"
#include "rr_graph_tileable_builder.h" #include "rr_graph_tileable_builder.h"
@ -66,6 +65,13 @@
#include "rr_blocks.h" #include "rr_blocks.h"
#include "chan_node_details.h" #include "chan_node_details.h"
#include "device_coordinator.h" #include "device_coordinator.h"
#include "rr_graph_tileable_sbox.h"
/************************************************************************
* Local data stuctures in the file
***********************************************************************/
typedef std::vector<std::vector<std::vector<int>>> t_track2pin_map;
typedef std::vector<std::vector<std::vector<int>>> t_pin2track_map;
/************************************************************************ /************************************************************************
* Local function in the file * Local function in the file
@ -538,8 +544,11 @@ void load_one_node_to_rr_graph_fast_lookup(t_rr_graph* rr_graph, int node_index,
***********************************************************************/ ***********************************************************************/
static static
void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator, void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator,
const t_grid_tile& cur_grid, enum e_side io_side, const t_grid_tile& cur_grid,
t_rr_graph* rr_graph, size_t* cur_node_id) { enum e_side io_side,
t_rr_graph* rr_graph,
size_t* cur_node_id,
int wire_to_ipin_switch, int delayless_switch) {
Side io_side_manager(io_side); Side io_side_manager(io_side);
/* Walk through the height of each grid, /* Walk through the height of each grid,
* get pins and configure the rr_nodes */ * get pins and configure the rr_nodes */
@ -565,6 +574,10 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator
rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin];
rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].capacity = 1;
rr_graph->rr_node[*cur_node_id].occ = 0; rr_graph->rr_node[*cur_node_id].occ = 0;
/* cost index is a FIXED value for OPIN */
rr_graph->rr_node[*cur_node_id].cost_index = OPIN_COST_INDEX;
/* Switch info */
rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch;
/* fill fast look-up table */ /* fill fast look-up table */
load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id,
rr_graph->rr_node[*cur_node_id].type, rr_graph->rr_node[*cur_node_id].type,
@ -586,6 +599,10 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator
rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin];
rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].capacity = 1;
rr_graph->rr_node[*cur_node_id].occ = 0; rr_graph->rr_node[*cur_node_id].occ = 0;
/* cost index is a FIXED value for IPIN */
rr_graph->rr_node[*cur_node_id].cost_index = IPIN_COST_INDEX;
/* Switch info */
rr_graph->rr_node[*cur_node_id].driver_switch = wire_to_ipin_switch;
/* fill fast look-up table */ /* fill fast look-up table */
load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id,
rr_graph->rr_node[*cur_node_id].type, rr_graph->rr_node[*cur_node_id].type,
@ -612,6 +629,15 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator
/* FIXME: need to confirm if the capacity should be the number of pins in this class*/ /* FIXME: need to confirm if the capacity should be the number of pins in this class*/
rr_graph->rr_node[*cur_node_id].capacity = cur_grid.type->class_inf[iclass].num_pins; rr_graph->rr_node[*cur_node_id].capacity = cur_grid.type->class_inf[iclass].num_pins;
rr_graph->rr_node[*cur_node_id].occ = 0; rr_graph->rr_node[*cur_node_id].occ = 0;
/* cost index is a FIXED value for SOURCE and SINK */
if (SOURCE == rr_graph->rr_node[*cur_node_id].type) {
rr_graph->rr_node[*cur_node_id].cost_index = SOURCE_COST_INDEX;
}
if (SINK == rr_graph->rr_node[*cur_node_id].type) {
rr_graph->rr_node[*cur_node_id].cost_index = SINK_COST_INDEX;
}
/* Switch info */
rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch;
/* TODO: should we set pb_graph_pin here? */ /* TODO: should we set pb_graph_pin here? */
/* fill fast look-up table */ /* fill fast look-up table */
load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id,
@ -635,8 +661,10 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator
***********************************************************************/ ***********************************************************************/
static static
void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator, void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator,
t_rr_type chan_type, const t_rr_type chan_type,
ChanNodeDetails* chan_details, ChanNodeDetails* chan_details,
const std::vector<t_segment_inf> segment_infs,
const int cost_index_offset,
t_rr_graph* rr_graph, t_rr_graph* rr_graph,
size_t* cur_node_id) { size_t* cur_node_id) {
/* Check each node_id(potential ptc_num) in the channel : /* Check each node_id(potential ptc_num) in the channel :
@ -657,8 +685,13 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator
rr_graph->rr_node[*cur_node_id].track_ids.push_back(itrack); rr_graph->rr_node[*cur_node_id].track_ids.push_back(itrack);
rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].capacity = 1;
rr_graph->rr_node[*cur_node_id].occ = 0; rr_graph->rr_node[*cur_node_id].occ = 0;
/* assign switch id */
size_t seg_id = chan_details->get_track_segment_id(itrack);
rr_graph->rr_node[*cur_node_id].driver_switch = segment_infs[seg_id].opin_switch;
/* Update chan_details with node_id */ /* Update chan_details with node_id */
chan_details->set_track_node_id(itrack, *cur_node_id); chan_details->set_track_node_id(itrack, *cur_node_id);
/* cost index depends on the segment index */
rr_graph->rr_node[*cur_node_id].cost_index = cost_index_offset + seg_id;
/* Update node counter */ /* Update node counter */
(*cur_node_id)++; (*cur_node_id)++;
/* Finish here, go to next */ /* Finish here, go to next */
@ -677,6 +710,11 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator
rr_graph->rr_node[*cur_node_id].occ = 0; rr_graph->rr_node[*cur_node_id].occ = 0;
/* Update chan_details with node_id */ /* Update chan_details with node_id */
chan_details->set_track_node_id(itrack, *cur_node_id); chan_details->set_track_node_id(itrack, *cur_node_id);
/* assign switch id */
size_t seg_id = chan_details->get_track_segment_id(itrack);
rr_graph->rr_node[*cur_node_id].driver_switch = segment_infs[seg_id].opin_switch;
/* cost index depends on the segment index */
rr_graph->rr_node[*cur_node_id].cost_index = cost_index_offset + seg_id;
/* Update node counter */ /* Update node counter */
(*cur_node_id)++; (*cur_node_id)++;
/* Finish here, go to next */ /* Finish here, go to next */
@ -755,7 +793,8 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph,
const DeviceCoordinator& device_size, const DeviceCoordinator& device_size,
std::vector<std::vector<t_grid_tile>> grids, std::vector<std::vector<t_grid_tile>> grids,
std::vector<size_t> chan_width, std::vector<size_t> chan_width,
std::vector<t_segment_inf> segment_infs) { std::vector<t_segment_inf> segment_infs,
int wire_to_ipin_switch, int delayless_switch) {
/* counter */ /* counter */
size_t cur_node_id = 0; size_t cur_node_id = 0;
/* configure by node type */ /* configure by node type */
@ -780,7 +819,8 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph,
} }
/* Configure rr_nodes for this grid */ /* Configure rr_nodes for this grid */
load_one_grid_rr_nodes_basic_info(grid_coordinator, grid[ix][iy], io_side, load_one_grid_rr_nodes_basic_info(grid_coordinator, grid[ix][iy], io_side,
rr_graph, &cur_node_id); rr_graph, &cur_node_id,
wire_to_ipin_switch, delayless_switch);
} }
} }
@ -799,7 +839,10 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph,
} }
ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, chan_side, segment_infs); ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, chan_side, segment_infs);
/* Configure CHANX in this channel */ /* Configure CHANX in this channel */
load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, &chanx_details, load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX,
&chanx_details,
segment_infs,
CHANX_COST_INDEX_START,
rr_graph, &cur_node_id); rr_graph, &cur_node_id);
/* Rotate the chanx_details by an offset of 1*/ /* Rotate the chanx_details by an offset of 1*/
/* For INC_DIRECTION, we use clockwise rotation /* For INC_DIRECTION, we use clockwise rotation
@ -834,7 +877,10 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph,
} }
ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, chan_side, segment_infs); ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, chan_side, segment_infs);
/* Configure CHANX in this channel */ /* Configure CHANX in this channel */
load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, &chany_details, load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY,
&chany_details,
segment_infs,
CHANX_COST_INDEX_START + segment_infs.size(),
rr_graph, &cur_node_id); rr_graph, &cur_node_id);
/* Rotate the chany_details by an offset of 1*/ /* Rotate the chany_details by an offset of 1*/
/* For INC_DIRECTION, we use clockwise rotation /* For INC_DIRECTION, we use clockwise rotation
@ -1341,11 +1387,9 @@ void add_one_edge_for_two_rr_nodes(t_rr_graph* rr_graph,
***********************************************************************/ ***********************************************************************/
static static
void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb,
std::vector < std::vector< std::vector<int> > > track2ipin_lookup, t_track2pin_map track2ipin_map,
std::vector < std::vector< std::vector<int> > > opin2track_map, t_pin2track_map opin2track_map,
std::vector < std::vector< std::vector<int> > > sb_conn, t_track2track_map track2track_map) {
int num_directs, t_clb_to_clb_directs* clb_to_clb_directs,
int num_switches, int delayless_switch) {
/* Check rr_gsb */ /* Check rr_gsb */
assert (NULL != rr_gsb); assert (NULL != rr_gsb);
@ -1353,6 +1397,7 @@ void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb,
for (size_t side = 0; side < rr_gsb->get_num_sides(); ++side) { for (size_t side = 0; side < rr_gsb->get_num_sides(); ++side) {
Side side_manager(side); Side side_manager(side);
enum e_side gsb_side = side_manager.get_side(); enum e_side gsb_side = side_manager.get_side();
/* Find OPINs */ /* Find OPINs */
for (size_t inode = 0; inode < rr_gsb->get_num_opin_nodes(gsb_side); ++inode) { for (size_t inode = 0; inode < rr_gsb->get_num_opin_nodes(gsb_side); ++inode) {
t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode); t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode);
@ -1362,42 +1407,69 @@ void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb,
rr_graph->rr_node_indices); rr_graph->rr_node_indices);
/* add edges to the src_node */ /* add edges to the src_node */
add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, opin_node - rr_graph->rr_node, add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, opin_node - rr_graph->rr_node,
delayless_switch); opin_node->driver_switch);
/* 2. create edges between OPINs and CHANX|CHANY, using opin2track_map */
int num_edges = opin2track_map[side_manager.to_size_t()][inode].size();
for (int iedge = 0; iedge < num_edges; ++iedge) {
int track_node_id = opin2track_map[side_manager.to_size_t()][inode][iedge];
/* add edges to the chan_node */
add_one_edge_for_two_rr_nodes(rr_graph, opin_node - rr_graph->rr_node, track_node_id,
rr_graph->rr_node[track_node_id].driver_switch);
} }
}
/* Find IPINs */ /* Find IPINs */
for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) { for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) {
t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode); t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode);
/* 2. create edges between IPINs and SINKs */ /* 3. create edges between IPINs and SINKs */
int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow, int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow,
SINK, ipin_node->ptc_num, SINK, ipin_node->ptc_num,
rr_graph->rr_node_indices); rr_graph->rr_node_indices);
/* add edges to connect the IPIN node to SINK nodes */ /* add edges to connect the IPIN node to SINK nodes */
add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id, add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id,
delayless_switch); rr_graph->rr_node[sink_node_id].driver_switch);
}
/* Find CHANX or CHANY */
for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) {
t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode);
/* 4. create edges between CHANX|CHANY and IPINs, using ipin2track_map */
int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size();
for (int iedge = 0; iedge < num_edges; ++iedge) {
int ipin_node_id = track2ipin_map[side_manager.to_size_t()][inode][iedge];
/* add edges to the chan_node */
add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, ipin_node_id,
rr_graph->rr_node[ipin_node_id].driver_switch);
}
/* 5. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */
num_edges = track2track_map[side_manager.to_size_t()][inode].size();
for (int iedge = 0; iedge < num_edges; ++iedge) {
int track_node_id = track2track_map[side_manager.to_size_t()][inode][iedge];
/* add edges to the chan_node */
add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, track_node_id,
rr_graph->rr_node[track_node_id].driver_switch);
}
} }
} }
/* 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) */
/* For TOP and BOTTOM */
return; return;
} }
/************************************************************************ /************************************************************************
* Convert the track_to_ipin_look[0..nodes_per_chan-1][0..height][0..3][pin_numbers] * Convert the pin_to_track_map[0..nodes_per_chan-1][0..height][0..3][pin_numbers]
* to the existing routing resources in the General Switch Block (GSB) * to the existing routing resources in the General Switch Block (GSB)
* The resulting matrix will be oragnized in * The resulting matrix will be oragnized in
* track2ipin_lookup[gsb_side][0..chan_width-1][ipin_indices] * pin2track_map[gsb_side][0..chan_width-1][ipin_indices]
***********************************************************************/ ***********************************************************************/
static static
std::vector < std::vector< std::vector<int> > > build_gsb_track_to_ipin_lookup(const RRGSB& rr_gsb, t_pin2track_map build_gsb_pin_to_track_map(const RRGSB& rr_gsb,
std::vector< std::vector<t_grid_tile> > grids, std::vector< std::vector<t_grid_tile> > grids,
int** Fc_in, int** Fc,
int***** ipin_to_track_map) { bool is_Fc_out,
std::vector < std::vector< std::vector<int> > > track2ipin_lookup; /* [0..gsb_side][0..num_tracks][0..Fc-1] */ int***** pin_to_track_map) {
/* [0..gsb_side][0..num_tracks][0..Fc-1] */
t_pin2track_map pin2track_map;
/* Resize the matrix */ /* Resize the matrix */
track2ipin_lookup.resize(rr_gsb.get_num_sides()); pin2track_map.resize(rr_gsb.get_num_sides());
/* Walk through each side */ /* Walk through each side */
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
@ -1405,28 +1477,151 @@ std::vector < std::vector< std::vector<int> > > build_gsb_track_to_ipin_lookup(c
enum e_side gsb_side = side_manager.get_side(); enum e_side gsb_side = side_manager.get_side();
/* Get channel width and resize the matrix */ /* Get channel width and resize the matrix */
size_t chan_width = rr_gsb.get_chan_width(gsb_side); size_t chan_width = rr_gsb.get_chan_width(gsb_side);
track2ipin_lookup[side].resize(chan_width); pin2track_map[side].resize(chan_width);
/* Find the ipin nodes */ /* Find the ipin/opin nodes */
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(gsb_side); ++inode) { size_t num_pin_nodes;
t_rr_node* ipin_node = rr_gsb.get_ipin_node(gsb_side, inode); if (true == is_Fc_out) { /* Fc_out, we consider OPINs */
num_pin_nodes = rr_gsb.get_num_opin_nodes(gsb_side);
} else { /* Fc_in, we consider IPINs */
num_pin_nodes = rr_gsb.get_num_ipin_nodes(gsb_side);
}
for (size_t inode = 0; inode < num_pin_nodes; ++inode) {
t_rr_node* pin_node;
if (true == is_Fc_out) { /* Fc_out, we consider OPINs */
pin_node = rr_gsb.get_opin_node(gsb_side, inode);
} else { /* Fc_in, we consider IPINs */
pin_node = rr_gsb.get_ipin_node(gsb_side, inode);
}
/* For each IPIN, we find the type_descriptor, offset and pin_side on the grid */ /* For each IPIN, we find the type_descriptor, offset and pin_side on the grid */
int grid_type_id = grids[ipin_node->xlow][ipin_node->ylow].type->index; int grid_type_id = grids[pin_node->xlow][pin_node->ylow].type->index;
int offset = grid[ipin_node->xlow][ipin_node->ylow].offset; int offset = grid[pin_node->xlow][pin_node->ylow].offset;
enum e_side pin_side = rr_gsb.get_ipin_node_grid_side(gsb_side, inode); enum e_side pin_side;
if (true == is_Fc_out) { /* Fc_out, we consider OPINs */
pin_side = rr_gsb.get_opin_node_grid_side(gsb_side, inode);
} else { /* Fc_in, we consider IPINs */
pin_side = rr_gsb.get_ipin_node_grid_side(gsb_side, inode);
}
/* Now, we fill the return matrix */ /* Now, we fill the return matrix */
/* Bypass empty array */ /* Bypass empty array */
if (NULL == ipin_to_track_map[grid_type_id][ipin_node->ptc_num][offset][0]) { if (NULL == pin_to_track_map[grid_type_id][pin_node->ptc_num][offset][0]) {
continue; continue;
} }
/* Get each track_id */ /* Get each track_id */
for (int iconn = 0; iconn < Fc_in[grid_type_id][ipin_node->ptc_num]; ++iconn) { for (int iconn = 0; iconn < Fc[grid_type_id][pin_node->ptc_num]; ++iconn) {
int track_id = ipin_to_track_map[grid_type_id][ipin_node->ptc_num][offset][pin_side][iconn]; int track_id = pin_to_track_map[grid_type_id][pin_node->ptc_num][offset][pin_side][iconn];
track2ipin_lookup[gsb_side][track_id].push_back(inode); pin2track_map[gsb_side][track_id].push_back(inode);
} }
} }
} }
return track2ipin_lookup; return pin2track_map;
}
/************************************************************************
* Build the track_to_ipin_map[gsb_side][0..chan_width-1][ipin_indices]
* based on the existing routing resources in the General Switch Block (GSB)
* This function supports both X-directional and Y-directional tracks
* The mapping is done in the following steps:
* 1. build a list of routing tracks which are allowed for connections
* We will check the Connection Block (CB) population of each routing track.
* By comparing current chan_y - ylow, we can determine if a CB connection
* is required for each routing track
* 2. Divide the routing tracks by segment types, so that we can balance
* the connections between IPINs and different types of routing tracks.
* 3. Scale the Fc of each pin to the actual number of routing tracks
* actual_Fc = (int) Fc * num_tracks / chan_width
* 4. Build ipin_to_track_map[gsb_side][0..num_ipin_nodes-1][track_indices]
* For each IPIN, we ensure at least one connection to the tracks.
* Then, we assign IPINs to tracks evenly while satisfying the actual_Fc
* 5. Convert the ipin_to_track_map to track_to_ipin_map
***********************************************************************/
/************************************************************************
* Build the opin_to_track_map[gsb_side][0..num_opin_nodes-1][track_indices]
* based on the existing routing resources in the General Switch Block (GSB)
* This function supports both X-directional and Y-directional tracks
* The mapping is done in the following steps:
* 1. Build a list of routing tracks whose starting points locate at this GSB
* (xlow - gsb_x == 0)
* 2. Divide the routing tracks by segment types, so that we can balance
* the connections between OPINs and different types of routing tracks.
* 3. Scale the Fc of each pin to the actual number of routing tracks
* actual_Fc = (int) Fc * num_tracks / chan_width
***********************************************************************/
/************************************************************************
* Add all direct clb-pin-to-clb-pin edges to given opin
***********************************************************************/
static
void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph,
const DeviceCoordinator& device_size,
const DeviceCoordinator& from_grid_coordinator,
const t_grid_tile& from_grid,
const int delayless_switch,
const int num_directs,
const t_direct_inf *directs,
const t_clb_to_clb_directs *clb_to_clb_directs) {
t_type_ptr grid_type = from_grid.type;
/* Iterate through all direct connections */
for (int i = 0; i < num_directs; ++i) {
/* Bypass unmatched direct clb-to-clb connections */
if (grid_type != clb_to_clb_directs[i].from_clb_type) {
continue;
}
bool swap;
int max_index, min_index;
/* Compute index of opin with regards to given pins */
if ( clb_to_clb_directs[i].from_clb_pin_start_index
> clb_to_clb_directs[i].from_clb_pin_end_index) {
swap = true;
max_index = clb_to_clb_directs[i].from_clb_pin_start_index;
min_index = clb_to_clb_directs[i].from_clb_pin_end_index;
} else {
swap = false;
min_index = clb_to_clb_directs[i].from_clb_pin_start_index;
max_index = clb_to_clb_directs[i].from_clb_pin_end_index;
}
/* get every opin in the range */
for (int opin = min_index; opin <= max_index; ++opin) {
int offset = opin - min_index;
/* This opin is specified to connect directly to an ipin, now compute which ipin to connect to */
DeviceCoordinator to_grid_coordinator(from_grid_coordinator.get_x() + directs[i].x_offset,
from_grid_coordinator.get_y() + directs[i].y_offset);
if ( (to_grid_coordinator.get_x() < device_size.get_x() - 1)
&& (to_grid_coordinator.get_y() < device_size.get_y() - 1) ) {
int ipin = OPEN;
if ( clb_to_clb_directs[i].to_clb_pin_start_index
> clb_to_clb_directs[i].to_clb_pin_end_index) {
if (true == swap) {
ipin = clb_to_clb_directs[i].to_clb_pin_end_index + offset;
} else {
ipin = clb_to_clb_directs[i].to_clb_pin_start_index - offset;
}
} else {
if(true == swap) {
ipin = clb_to_clb_directs[i].to_clb_pin_end_index - offset;
} else {
ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset;
}
}
/* Get the pin index in the rr_graph */
int from_grid_ofs = from_grid.offset;
int to_grid_ofs = grid[to_grid_coordinator.get_x()][to_grid_coordinator.get_y()].offset;
int opin_node_id = get_rr_node_index(from_grid_coordinator.get_x(),
from_grid_coordinator.get_y() - from_grid_ofs,
OPIN, opin, rr_graph->rr_node_indices);
int ipin_node_id = get_rr_node_index(to_grid_coordinator.get_x(),
to_grid_coordinator.get_y() - to_grid_ofs,
IPIN, ipin, rr_graph->rr_node_indices);
/* add edges to the opin_node */
add_one_edge_for_two_rr_nodes(rr_graph, opin_node_id, ipin_node_id,
delayless_switch);
}
}
}
return;
} }
@ -1448,31 +1643,36 @@ void build_rr_graph_edges(t_rr_graph* rr_graph,
std::vector< std::vector<t_grid_tile> > grids, std::vector< std::vector<t_grid_tile> > grids,
std::vector<size_t> device_chan_width, std::vector<size_t> device_chan_width,
std::vector<t_segment_inf> segment_inf, std::vector<t_segment_inf> segment_inf,
int L_num_types, t_type_ptr types,
int** Fc_in, int** Fc_out, int** Fc_in, int** Fc_out,
int***** ipin_to_track_map, int***** opin_to_track_map, int***** ipin_to_track_map, int***** opin_to_track_map,
vtr::NdMatrix<std::vector<int>,3> switch_block_conn, enum e_switch_block_type sb_type, int Fs) {
int num_directs, t_clb_to_clb_directs* clb_to_clb_directs,
int num_switches, int delayless_switch) {
DeviceCoordinator device_range(device_size.get_x() - 1, device_size.get_y() - 1); DeviceCoordinator device_range(device_size.get_x() - 1, device_size.get_y() - 1);
/* Go Switch Block by Switch Block */ /* Go Switch Block by Switch Block */
for (size_t ix = 0; ix < device_size.get_x(); ++ix) { for (size_t ix = 0; ix < device_size.get_x(); ++ix) {
for (size_t iy = 0; iy < device_size.get_y(); ++iy) { for (size_t iy = 0; iy < device_size.get_y(); ++iy) {
DeviceCoordinator gsb_coordinator(ix, iy); DeviceCoordinator gsb_coordinator(ix, iy);
/* Create a GSB object */ /* Create a GSB object */
RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph);
/* adapt the track_to_ipin_lookup for the GSB nodes */ /* adapt the track_to_ipin_lookup for the GSB nodes */
std::vector < std::vector< std::vector<int> > > track2ipin_lookup; /* [0..gsb_side][0..num_tracks][0..Fc-1] */ t_pin2track_map ipin2track_map; /* [0..track_gsb_side][0..num_tracks][ipin_indices] */
track2ipin_lookup = build_gsb_track_to_ipin_lookup(rr_gsb, grids, Fc_in, ipin_to_track_map); ipin2track_map = build_gsb_pin_to_track_map(rr_gsb, grids, Fc_in, false, ipin_to_track_map);
/* adapt the opin_to_track_map for the GSB nodes */ /* adapt the opin_to_track_map for the GSB nodes */
std::vector < std::vector< std::vector<int> > > opin2track_map; /* [0..gsb_side][0..num_opin_node][0..Fc-1] */ t_pin2track_map opin2track_map; /* [0..gsb_side][0..num_opin_node][track_indices] */
opin2track_map = build_gsb_pin_to_track_map(rr_gsb, grids, Fc_out, true, opin_to_track_map);
/* adapt the switch_block_conn for the GSB nodes */ /* adapt the switch_block_conn for the GSB nodes */
std::vector < std::vector< std::vector<int> > > sb_conn; /* [0..from_gsb_side][0..to_gsb_side][0..chan_width-1] */ t_track2track_map sb_conn; /* [0..from_gsb_side][0..chan_width-1][track_indices] */
sb_conn = build_gsb_track_to_track_map(rr_graph, rr_gsb, sb_type, Fs, segment_inf);
/* Build edges for a GSB */ /* Build edges for a GSB */
build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb,
track2ipin_lookup, opin2track_map, sb_conn, ipin2track_map, opin2track_map,
num_directs, clb_to_clb_directs, sb_conn);
num_switches, delayless_switch);
/* Finish this GSB, go to the next*/ /* Finish this GSB, go to the next*/
} }
} }
@ -1480,6 +1680,39 @@ void build_rr_graph_edges(t_rr_graph* rr_graph,
return; return;
} }
/************************************************************************
* Build direct edges for Grids *
***********************************************************************/
static
void build_rr_graph_direct_connections(t_rr_graph* rr_graph,
const DeviceCoordinator& device_size,
std::vector< std::vector<t_grid_tile> > grids,
const int delayless_switch,
const int num_directs,
const t_direct_inf *directs,
const t_clb_to_clb_directs *clb_to_clb_directs) {
for (size_t ix = 0; ix < device_size.get_x(); ++ix) {
for (size_t iy = 0; iy < device_size.get_y(); ++iy) {
/* Skip EMPTY tiles */
if (EMPTY_TYPE == grids[ix][iy].type) {
continue;
}
/* Skip height>1 tiles (mostly heterogeneous blocks) */
if (0 < grids[ix][iy].offset) {
continue;
}
DeviceCoordinator from_grid_coordinator(ix, iy);
build_direct_connections_for_one_gsb(rr_graph, device_size,
from_grid_coordinator,
grids[ix][iy],
delayless_switch,
num_directs, directs, clb_to_clb_directs);
}
}
return;
}
/************************************************************************ /************************************************************************
* Main function of this file * Main function of this file
* Builder for a detailed uni-directional tileable rr_graph * Builder for a detailed uni-directional tileable rr_graph
@ -1524,7 +1757,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types,
INP struct s_grid_tile **L_grid, INP int chan_width, INP struct s_grid_tile **L_grid, INP int chan_width,
INP enum e_switch_block_type sb_type, INP int Fs, INP enum e_switch_block_type sb_type, INP int Fs,
INP int num_seg_types, INP int num_seg_types,
INP int num_switches, INP t_segment_inf * segment_inf, INP t_segment_inf * segment_inf,
INP int delayless_switch, INP int delayless_switch,
INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, INP t_timing_inf timing_inf, INP int wire_to_ipin_switch,
INP enum e_base_cost_type base_cost_type, INP enum e_base_cost_type base_cost_type,
@ -1593,14 +1826,15 @@ void build_tileable_unidir_rr_graph(INP int L_num_types,
* grid_info : pb_graph_pin * grid_info : pb_graph_pin
***********************************************************************/ ***********************************************************************/
alloc_rr_graph_fast_lookup(device_size, &rr_graph); alloc_rr_graph_fast_lookup(device_size, &rr_graph);
load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs); load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs,
wire_to_ipin_switch, delayless_switch);
/************************************************************************ /************************************************************************
* 3.1 Create the connectivity of OPINs * 5.1 Create the connectivity of OPINs
* a. Evenly assign connections to OPINs to routing tracks * a. Evenly assign connections to OPINs to routing tracks
* b. the connection pattern should be same across the fabric * b. the connection pattern should be same across the fabric
* *
* 3.2 Create the connectivity of IPINs * 5.2 Create the connectivity of IPINs
* a. Evenly assign connections from routing tracks to IPINs * a. Evenly assign connections from routing tracks to IPINs
* b. the connection pattern should be same across the fabric * b. the connection pattern should be same across the fabric
***********************************************************************/ ***********************************************************************/
@ -1639,11 +1873,6 @@ void build_tileable_unidir_rr_graph(INP int L_num_types,
opin_to_track_map[i] = alloc_and_load_pin_to_track_map(DRIVER, chan_width, Fc_out[i], &types[i], FALSE, UNI_DIRECTIONAL); opin_to_track_map[i] = alloc_and_load_pin_to_track_map(DRIVER, chan_width, Fc_out[i], &types[i], FALSE, UNI_DIRECTIONAL);
} }
/************************************************************************
* 4. Build switch block connection matrix
***********************************************************************/
vtr::NdMatrix<std::vector<int>,3> switch_block_conn = alloc_and_load_tileable_switch_block_conn(chan_width, sb_type, Fs);
/************************************************************************ /************************************************************************
* 6. Build the connections tile by tile: * 6. Build the connections tile by tile:
* We classify rr_nodes into a general switch block (GSB) data structure * We classify rr_nodes into a general switch block (GSB) data structure
@ -1652,19 +1881,25 @@ void build_tileable_unidir_rr_graph(INP int L_num_types,
* In addition, we will also handle direct-connections: * In addition, we will also handle direct-connections:
* Add edges that bridge OPINs and IPINs to the rr_graph * Add edges that bridge OPINs and IPINs to the rr_graph
***********************************************************************/ ***********************************************************************/
/* Create edges for a tileable rr_graph */
build_rr_graph_edges(&rr_graph, device_size, grids, device_chan_width, segment_infs,
Fc_in, Fc_out, ipin_to_track_map, opin_to_track_map,
sb_type, Fs);
/************************************************************************
* 7. Build direction connection lists
***********************************************************************/
/* Create data structure of direct-connections */ /* Create data structure of direct-connections */
t_clb_to_clb_directs* clb_to_clb_directs = NULL; t_clb_to_clb_directs* clb_to_clb_directs = NULL;
if (num_directs > 0) { if (num_directs > 0) {
clb_to_clb_directs = alloc_and_load_clb_to_clb_directs(directs, num_directs); clb_to_clb_directs = alloc_and_load_clb_to_clb_directs(directs, num_directs);
} }
build_rr_graph_direct_connections(&rr_graph, device_size, grids, delayless_switch,
/* Create edges for a tileable rr_graph */ num_directs, directs, clb_to_clb_directs);
build_rr_graph_edges(&rr_graph, device_size, grids, device_chan_width, segment_infs,
L_num_types, types, Fc_in, Fc_out, ipin_to_track_map, opin_to_track_map, switch_block_conn,
num_directs, clb_to_clb_directs, num_switches, delayless_switch);
/************************************************************************ /************************************************************************
* 7. Allocate external data structures * 8. Allocate external data structures
* a. cost_index * a. cost_index
* b. RC tree * b. RC tree
***********************************************************************/ ***********************************************************************/
@ -1672,7 +1907,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types,
wire_to_ipin_switch, base_cost_type); wire_to_ipin_switch, base_cost_type);
/************************************************************************ /************************************************************************
* 8. Sanitizer for the rr_graph, check connectivities of rr_nodes * 9. Sanitizer for the rr_graph, check connectivities of rr_nodes
***********************************************************************/ ***********************************************************************/
/* We set global variables for rr_nodes here, /* We set global variables for rr_nodes here,
@ -1682,7 +1917,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types,
rr_node_indices = rr_graph.rr_node_indices; rr_node_indices = rr_graph.rr_node_indices;
/************************************************************************ /************************************************************************
* 9. Free all temp stucts * 10. Free all temp stucts
***********************************************************************/ ***********************************************************************/
/* Free all temp structs */ /* Free all temp structs */

View File

@ -6,7 +6,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types,
INP struct s_grid_tile **L_grid, INP int chan_width, INP struct s_grid_tile **L_grid, INP int chan_width,
INP enum e_switch_block_type sb_type, INP int Fs, INP enum e_switch_block_type sb_type, INP int Fs,
INP int num_seg_types, INP int num_seg_types,
INP int num_switches, INP t_segment_inf * segment_inf, INP t_segment_inf * segment_inf,
INP int delayless_switch, INP int delayless_switch,
INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, INP t_timing_inf timing_inf, INP int wire_to_ipin_switch,
INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs,

View File

@ -1,211 +1,461 @@
#include "vtr_assert.h" /**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
#include "vtr_util.h" /************************************************************************
#include "vtr_memory.h" * Filename: rr_graph_tileable_sbox.cpp
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/19 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* This file contains a builder for track-to-track connections inside a
* tileable General Switch Block (GSB).
***********************************************************************/
#include <cstdlib>
#include <cassert>
#include <vector>
#include "vpr_types.h" #include "vpr_types.h"
#include "rr_graph_tileable_sbox.h" #include "rr_graph_tileable_sbox.h"
#include "rr_graph_util.h"
#include "ReadOptions.h"
static
int get_tileable_simple_switch_block_track(const enum e_side from_side,
const enum e_side to_side, const int from_track,
const enum e_switch_block_type switch_block_type, const int nodes_per_chan);
/************************************************************************ /************************************************************************
* Build internal connection pattern for a switch block * Internal data structures
* This function is adapt to fit the tileable routing context from
* rr_graph_sbox.c : alloc_and_load_switch_block_conn
* Switch box: *
* TOP (CHANY) *
* | | | | | | *
* +-----------+ *
* --| |-- *
* --| |-- *
* LEFT --| |-- RIGHT *
* (CHANX)--| |--(CHANX) *
* --| |-- *
* --| |-- *
* +-----------+ *
* | | | | | | *
* BOTTOM (CHANY) *
*
* [0..3][0..3][0..nodes_per_chan-1]. Structure below is indexed as: *
* [from_side][to_side][from_track]. That yields an integer vector (ivec) *
* of the tracks to which from_track connects in the proper to_location. *
* For simple switch boxes this is overkill, but it will allow complicated *
* switch boxes with Fs > 3, etc. without trouble. *
***********************************************************************/ ***********************************************************************/
typedef std::vector<std::vector<int>> t_track_group;
/* Allocates and loads the switch_block_conn data structure. This structure * /************************************************************************
* lists which tracks connect to which at each switch block. This is for * A enumeration to list the status of a track inside a GSB
* bidir. */ * 1. start; 2. end; 3. passing
vtr::NdMatrix<std::vector<int>,3> alloc_and_load_tileable_switch_block_conn(const size_t nodes_per_chan, * This is used to group tracks which ease the building of
const e_switch_block_type switch_block_type, * track-to-track mapping matrix
const int Fs) { ***********************************************************************/
enum e_track_status {
TRACK_START,
TRACK_END,
TRACK_PASS,
NUM_TRACK_STATUS /* just a place holder to get the number of status */
};
/* Currently Fs must be 3 since each track maps once to each other side */ /************************************************************************
VTR_ASSERT(3 == Fs); * Check if a track starts from this GSB or not
* (xlow, ylow) should be same as the GSB side coordinator
vtr::NdMatrix<std::vector<int>,3> switch_block_conn({4, 4, nodes_per_chan}); *
* Check if a track ends at this GSB or not
for (e_side from_side : {TOP, RIGHT, BOTTOM, LEFT}) { * (xhigh, yhigh) should be same as the GSB side coordinator
for (e_side to_side : {TOP, RIGHT, BOTTOM, LEFT}) { ***********************************************************************/
for (size_t from_track = 0; from_track < nodes_per_chan; from_track++) {
if (from_side != to_side) {
switch_block_conn[from_side][to_side][from_track].resize(1);
switch_block_conn[from_side][to_side][from_track][0] = get_tileable_simple_switch_block_track(from_side, to_side,
from_track, switch_block_type, nodes_per_chan);
} else { /* from_side == to_side -> no connection. */
switch_block_conn[from_side][to_side][from_track].clear();
}
}
}
}
if (getEchoEnabled()) {
FILE *out = vtr::fopen("switch_block_conn.echo", "w");
for (int l = 0; l < 4; ++l) {
for (int k = 0; k < 4; ++k) {
fprintf(out, "Side %d to %d\n", l, k);
for (size_t j = 0; j < nodes_per_chan; ++j) {
fprintf(out, "%zu: ", j);
for (unsigned i = 0; i < switch_block_conn[l][k][j].size(); ++i) {
fprintf(out, "%d ", switch_block_conn[l][k][j][i]);
}
fprintf(out, "\n");
}
fprintf(out, "\n");
}
}
fclose(out);
}
return switch_block_conn;
}
#define SBOX_ERROR -1
/* This routine permutes the track number to connect for topologies
* SUBSET, UNIVERSAL, and WILTON. I added FULL (for fully flexible topology)
* but the returned value is simply a dummy, since we don't need to permute
* what connections to make for FULL (connect to EVERYTHING) */
static static
int get_tileable_simple_switch_block_track(const enum e_side from_side, enum e_track_status determine_track_status_of_gsb(const RRGSB& rr_gsb,
const enum e_side to_side, const int from_track, const enum e_side gsb_side,
const enum e_switch_block_type switch_block_type, const int nodes_per_chan) { const size_t track_id) {
enum e_track_status track_status = TRACK_PASS;
/* Get the rr_node */
t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id);
/* Get the coordinators */
DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side);
/* This routine returns the track number to which the from_track should * /* INC_DIRECTION start_track: (xlow, ylow) should be same as the GSB side coordinator */
* connect. It supports three simple, Fs = 3, switch blocks. */ if ( ((size_t)track_node->xlow == side_coordinator.get_x())
&& ((size_t)track_node->ylow == side_coordinator.get_y())
int to_track = SBOX_ERROR; /* Can check to see if it's not set later. */ && (OUT_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) {
/* Double check: start track should be an OUTPUT PORT of the GSB */
if (switch_block_type == SUBSET) { /* NB: Global routing uses SUBSET too */ track_status = TRACK_START;
to_track = from_track; }
/* INC_DIRECTION end_track: (xhigh, yhigh) should be same as the GSB side coordinator */
if ( ((size_t)track_node->xhigh == side_coordinator.get_x())
&& ((size_t)track_node->yhigh == side_coordinator.get_y())
&& (IN_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) {
/* Double check: end track should be an INPUT PORT of the GSB */
track_status = TRACK_END;
} }
/* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ return track_status;
}
else if (switch_block_type == WILTON) { /************************************************************************
* Check if the GSB is in the Switch Block (SB) population list of the segment
* SB population of a L3 wire: 1 0 0 1
*
* +----+ +----+ +----+ +----+
* | SB |--->| SB |--->| SB |--->| SB |
* +----+ +----+ +----+ +----+
* Engage SB connection Yes No No Yes
*
* We will find the offset between gsb_side_coordinator and (xlow,ylow) of the track
* Use the offset to check if the tracks should engage in this GSB connection
***********************************************************************/
static
bool is_gsb_in_track_sb_population(const RRGSB& rr_gsb,
const enum e_side gsb_side,
const int track_id,
const std::vector<t_segment_inf> segment_inf) {
/* Get the rr_node */
t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id);
/* Get the coordinators */
DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side);
if (from_side == LEFT) { /* Get the offset */
size_t offset = (side_coordinator.get_x() - track_node->xlow)
+ (side_coordinator.get_y() - track_node->ylow);
if (to_side == RIGHT) { /* CHANX to CHANX */ /* Get segment id */
to_track = from_track; size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id);
} else if (to_side == TOP) { /* from CHANX to CHANY */ /* validate offset */
to_track = (nodes_per_chan - (from_track % nodes_per_chan)) % nodes_per_chan; assert (offset < (size_t)segment_inf[seg_id].sb_len);
} else if (to_side == BOTTOM) {
to_track = (nodes_per_chan + from_track - 1) % nodes_per_chan; /* Get the SB population */
bool in_sb_population = false;
if (TRUE == segment_inf[seg_id].sb[offset]) {
in_sb_population = true;
}
return in_sb_population;
}
/************************************************************************
* Create a list of track_id based on the to_track and num_to_tracks
* We consider the following list [to_track, to_track + Fs/3 - 1]
* if the [to_track + Fs/3 - 1] exceeds the num_to_tracks, we start over from 0!
***********************************************************************/
static
std::vector<size_t> get_to_track_list(const int Fs, const int to_track, const int num_to_tracks) {
std::vector<size_t> to_tracks;
for (int i = 0; i < Fs; i = i + 3) {
/* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied
* The optimal track selection should be done in a more scientific way!!!
*/
size_t to_track_i = to_track + i;
/* make sure the track id is still in range */
if ( to_track_i > (size_t)num_to_tracks) {
to_track_i = to_track_i % num_to_tracks;
}
/* from track must be connected */
to_tracks.push_back(to_track_i);
}
return to_tracks;
}
/************************************************************************
* This function aims to return the track indices that drive the from_track
* in a Switch Block
* The track_ids to return will depend on different topologies of SB
* SUBSET, UNIVERSAL, and WILTON.
***********************************************************************/
static
std::vector<size_t> get_switch_block_to_track_id(const enum e_switch_block_type switch_block_type,
const int Fs,
const enum e_side from_side,
const int from_track,
const enum e_side to_side,
const int num_to_tracks) {
/* This routine returns the track number to which the from_track should
* connect. It supports any Fs % 3 == 0, switch blocks.
*/
std::vector<size_t> to_tracks;
/* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied
* The optimal track selection should be done in a more scientific way!!!
*/
assert (0 == Fs % 3);
switch (switch_block_type) {
case SUBSET: /* NB: Global routing uses SUBSET too */
to_tracks = get_to_track_list(Fs, from_track, num_to_tracks);
/* Finish, we return */
return to_tracks;
case UNIVERSAL:
if ( (from_side == LEFT)
|| (from_side == RIGHT) ) {
/* For the prev_side, to_track is from_track
* For the next_side, to_track is num_to_tracks - 1 - from_track
* For the opposite_side, to_track is always from_track
*/
Side side_manager(from_side);
if ( (to_side == side_manager.get_opposite())
|| (to_side == side_manager.get_rotate_counterclockwise()) ) {
to_tracks = get_to_track_list(Fs, from_track, num_to_tracks);
} else if (to_side == side_manager.get_rotate_clockwise()) {
to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks);
} }
} }
else if (from_side == RIGHT) { if ( (from_side == TOP)
if (to_side == LEFT) { /* CHANX to CHANX */ || (from_side == BOTTOM) ) {
to_track = from_track; /* For the next_side, to_track is from_track
} else if (to_side == TOP) { /* from CHANX to CHANY */ * For the prev_side, to_track is num_to_tracks - 1 - from_track
to_track = (nodes_per_chan + from_track - 1) % nodes_per_chan; * For the opposite_side, to_track is always from_track
} else if (to_side == BOTTOM) { */
to_track = (2 * nodes_per_chan - 2 - from_track) % nodes_per_chan; Side side_manager(from_side);
if ( (to_side == side_manager.get_opposite())
|| (to_side == side_manager.get_rotate_clockwise()) ) {
to_tracks = get_to_track_list(Fs, from_track, num_to_tracks);
} else if (to_side == side_manager.get_rotate_counterclockwise()) {
to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks);
} }
} }
/* Finish, we return */
else if (from_side == BOTTOM) { return to_tracks;
if (to_side == TOP) { /* CHANY to CHANY */
to_track = from_track;
} else if (to_side == LEFT) { /* from CHANY to CHANX */
to_track = (from_track + 1) % nodes_per_chan;
} else if (to_side == RIGHT) {
to_track = (2 * nodes_per_chan - 2 - from_track) % nodes_per_chan;
}
}
else if (from_side == TOP) {
if (to_side == BOTTOM) { /* CHANY to CHANY */
to_track = from_track;
} else if (to_side == LEFT) { /* from CHANY to CHANX */
to_track = (nodes_per_chan - (from_track % nodes_per_chan)) % nodes_per_chan;
} else if (to_side == RIGHT) {
to_track = (from_track + 1) % nodes_per_chan;
}
}
/* Force to_track to UN_SET if it falls outside the min/max channel width range */
if (to_track < 0 || to_track >= nodes_per_chan) {
to_track = -1;
}
}
/* End switch_block_type == WILTON case. */
else if (switch_block_type == UNIVERSAL) {
if (from_side == LEFT) {
if (to_side == RIGHT) { /* CHANX to CHANX */
to_track = from_track;
} else if (to_side == TOP) { /* from CHANX to CHANY */
to_track = nodes_per_chan - 1 - from_track;
} else if (to_side == BOTTOM) {
to_track = from_track;
}
}
else if (from_side == RIGHT) {
if (to_side == LEFT) { /* CHANX to CHANX */
to_track = from_track;
} else if (to_side == TOP) { /* from CHANX to CHANY */
to_track = from_track;
} else if (to_side == BOTTOM) {
to_track = nodes_per_chan - 1 - from_track;
}
}
else if (from_side == BOTTOM) {
if (to_side == TOP) { /* CHANY to CHANY */
to_track = from_track;
} else if (to_side == LEFT) { /* from CHANY to CHANX */
to_track = from_track;
} else if (to_side == RIGHT) {
to_track = nodes_per_chan - 1 - from_track;
}
}
else if (from_side == TOP) {
if (to_side == BOTTOM) { /* CHANY to CHANY */
to_track = from_track;
} else if (to_side == LEFT) { /* from CHANY to CHANX */
to_track = nodes_per_chan - 1 - from_track;
} else if (to_side == RIGHT) {
to_track = from_track;
}
}
}
/* End switch_block_type == UNIVERSAL case. */ /* End switch_block_type == UNIVERSAL case. */
/* UDSD Modification by WMF Begin */ case WILTON:
if (switch_block_type == FULL) { /* Just a placeholder. No meaning in reality */ /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */
to_track = from_track; if (from_side == LEFT) {
if (to_side == RIGHT) { /* CHANX to CHANX */
to_tracks = get_to_track_list(Fs, from_track, num_to_tracks);
} else if (to_side == TOP) { /* from CHANX to CHANY */
to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks);
} else if (to_side == BOTTOM) {
to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks);
}
} else if (from_side == RIGHT) {
if (to_side == LEFT) { /* CHANX to CHANX */
to_tracks = get_to_track_list(Fs, from_track, num_to_tracks);
} else if (to_side == TOP) { /* from CHANX to CHANY */
to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks);
} else if (to_side == BOTTOM) {
to_tracks = get_to_track_list(Fs, (num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks);
}
} else if (from_side == BOTTOM) {
if (to_side == TOP) { /* CHANY to CHANY */
to_tracks = get_to_track_list(Fs, from_track, num_to_tracks);
} else if (to_side == LEFT) { /* from CHANY to CHANX */
to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks);
} else if (to_side == RIGHT) {
to_tracks = get_to_track_list(Fs, (2 * num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks);
}
} else if (from_side == TOP) {
if (to_side == BOTTOM) { /* CHANY to CHANY */
to_tracks = get_to_track_list(Fs, from_track, num_to_tracks);
} else if (to_side == LEFT) { /* from CHANY to CHANX */
to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks);
} else if (to_side == RIGHT) {
to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks);
}
}
/* Finish, we return */
return to_tracks;
/* End switch_block_type == WILTON case. */
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d]) Invalid switch block pattern !\n",
__FILE__, __LINE__);
exit(1);
} }
/* UDSD Modification by WMF End */
return (to_track); return to_tracks;
} }
/************************************************************************
* Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices]
* For a group of from_track nodes and to_track nodes
* For each side of from_tracks, we call a routine to get the list of to_tracks
* Then, we fill the track2track_map
***********************************************************************/
static
void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph,
const RRGSB& rr_gsb,
const enum e_switch_block_type sb_type,
const int Fs,
const t_track_group from_tracks, /* [0..gsb_side][track_indices] */
const t_track_group to_tracks, /* [0..gsb_side][track_indices] */
t_track2track_map* track2track_map) {
for (size_t side = 0; side < from_tracks.size(); ++side) {
Side side_manager(side);
enum e_side gsb_side = side_manager.get_side();
/* Find the other sides where the start tracks will locate */
std::vector<enum e_side> to_track_sides;
/* 0. opposite side */
to_track_sides.push_back(side_manager.get_opposite());
/* 1. prev side */
/* Previous side definition: TOP => LEFT; RIGHT=>TOP; BOTTOM=>RIGHT; LEFT=>BOTTOM */
to_track_sides.push_back(side_manager.get_rotate_counterclockwise());
/* 2. next side */
/* Next side definition: TOP => RIGHT; RIGHT=>BOTTOM; BOTTOM=>LEFT; LEFT=>TOP */
to_track_sides.push_back(side_manager.get_rotate_clockwise());
for (size_t inode = 0; inode < from_tracks[side].size(); ++inode) {
for (size_t to_side_id = 0; to_side_id < to_track_sides.size(); ++to_side_id) {
enum e_side to_side = to_track_sides[to_side_id];
Side to_side_manager(to_side);
size_t to_side_index = to_side_manager.to_size_t();
/* Bypass those to_sides have no nodes */
if (0 == to_tracks[to_side_index].size()) {
continue;
}
/* Get other track_ids depending on the switch block pattern */
/* Find the track ids that will start at the other sides */
std::vector<size_t> to_track_ids = get_switch_block_to_track_id(sb_type, Fs, gsb_side, inode,
to_side,
to_tracks[to_side_index].size());
/* Update the track2track_map: */
for (size_t to_track_id = 0; to_track_id < to_track_ids.size(); ++to_track_id) {
size_t from_side_index = side_manager.to_size_t();
size_t from_track_index = from_tracks[side][inode];
size_t to_track_index = to_tracks[to_side_index][to_track_ids[to_track_id]];
t_rr_node* to_track_node = rr_gsb.get_chan_node(to_side, to_track_index);
(*track2track_map)[from_side_index][from_track_index].push_back(to_track_node - rr_graph->rr_node);
}
}
}
}
return;
}
/************************************************************************
* Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices]
* based on the existing routing resources in the General Switch Block (GSB)
* The track_indices is the indices of tracks that the node at from_side and [0..chan_width-1] will drive
* IMPORTANT: the track_indices are the indicies in the GSB context, but not the rr_graph!!!
* We separate the connections into two groups:
* Group 1: the routing tracks start from this GSB
* We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON)
* Group 2: the routing tracks do not start from this GSB (bypassing wires)
* We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON)
* but we will check the Switch Block (SB) population of these
* routing segments, and determine which requires connections
*
* CHANY CHANY CHANY CHANY
* [0] [1] [2] [3]
* start yes no yes no
* end +-------------------------+ start Group 1 Group 2
* no CHANX[0] | TOP | CHANX[0] yes TOP/BOTTOM TOP/BOTTOM
* | | CHANY[0,2] CHANY[1,3]
* yes CHANX[1] | | CHANX[1] no
* | LEFT RIGHT |
* no CHANX[2] | | CHANX[2] yes
* | |
* yes CHANX[3] | BOTTOM | CHANX[3] no
* +-------------------------+
* CHANY CHANY CHANY CHANY
* [0] [1] [2] [3]
* start yes no yes no
*
* The mapping is done in the following steps: (For each side of the GSB)
* 1. Build a list of tracks that will start from this side
* if a track starts, its xlow/ylow is the same as the x,y of this gsb
* 2. Build a list of tracks on the other sides belonging to Group 1.
* Take the example of RIGHT side, we will collect
* a. tracks that will end at the LEFT side
* b. tracks that will start at the TOP side
* c. tracks that will start at the BOTTOM side
* 3. Apply switch block patterns to Group 1 (SUBSET, UNIVERSAL, WILTON)
* 4. Build a list of tracks on the other sides belonging to Group 1.
* Take the example of RIGHT side, we will collect
* a. tracks that will bypass at the TOP side
* b. tracks that will bypass at the BOTTOM side
* 5. Apply switch block patterns to Group 2 (SUBSET, UNIVERSAL, WILTON)
***********************************************************************/
t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph,
const RRGSB& rr_gsb,
const enum e_switch_block_type sb_type,
const int Fs,
const std::vector<t_segment_inf> segment_inf) {
t_track2track_map track2track_map; /* [0..gsb_side][0..chan_width][track_indices] */
/* Categorize tracks into 3 groups:
* (1) tracks will start here
* (2) tracks will end here
* (2) tracks will just pass through the SB */
t_track_group start_tracks; /* [0..gsb_side][track_indices] */
t_track_group end_tracks; /* [0..gsb_side][track_indices] */
t_track_group pass_tracks; /* [0..gsb_side][track_indices] */
/* resize to the number of sides */
start_tracks.resize(rr_gsb.get_num_sides());
end_tracks.resize(rr_gsb.get_num_sides());
pass_tracks.resize(rr_gsb.get_num_sides());
/* Walk through each side */
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side side_manager(side);
enum e_side gsb_side = side_manager.get_side();
/* Build a list of tracks that will start from this side */
for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) {
/* check if this track will start from here */
enum e_track_status track_status = determine_track_status_of_gsb(rr_gsb, gsb_side, inode);
switch (track_status) {
case TRACK_START:
/* update starting track list */
start_tracks[gsb_side].push_back(inode);
break;
case TRACK_END:
/* Update end track list */
end_tracks[gsb_side].push_back(inode);
break;
case TRACK_PASS:
/* We need to check Switch block population of this track
* The track node will not be considered if there supposed to be no SB at this position
*/
if (true == is_gsb_in_track_sb_population(rr_gsb, gsb_side, inode, segment_inf)) {
/* Update passing track list */
pass_tracks[gsb_side].push_back(inode);
}
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d]) Invalid track status!\n",
__FILE__, __LINE__);
exit(1);
}
}
}
/* Allocate track2track map */
track2track_map.resize(rr_gsb.get_num_sides());
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side side_manager(side);
enum e_side gsb_side = side_manager.get_side();
/* allocate track2track_map[gsb_side] */
track2track_map[side].resize(rr_gsb.get_chan_width(gsb_side));
for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) {
/* allocate track2track_map[gsb_side][inode] */
track2track_map[side][inode].clear();
}
}
/* For Group 1: we build connections between end_tracks and start_tracks*/
build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb,
sb_type, Fs,
end_tracks, start_tracks,
&track2track_map);
/* For Group 2: we build connections between end_tracks and start_tracks*/
/* Currently, I use the same Switch Block pattern for the passing tracks and end tracks,
* TODO: This can be improved with different patterns!
*/
build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb,
sb_type, Fs,
pass_tracks, start_tracks,
&track2track_map);
return track2track_map;
}

View File

@ -5,8 +5,16 @@
#include "vtr_ndmatrix.h" #include "vtr_ndmatrix.h"
vtr::NdMatrix<std::vector<int>,3> alloc_and_load_tileable_switch_block_conn(size_t nodes_per_chan, #include "rr_blocks.h"
enum e_switch_block_type switch_block_type, int Fs); #include "fpga_x2p_types.h"
typedef std::vector<std::vector<std::vector<int>>> t_track2track_map;
t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph,
const RRGSB& rr_gsb,
const enum e_switch_block_type sb_type,
const int Fs,
const std::vector<t_segment_inf> segment_inf);
#endif #endif

View File

@ -1,3 +1,8 @@
#ifndef FPGA_X2P_TYPES_H
#define FPGA_X2P_TYPES_H
#include "route_common.h"
/* Define the basic data structures used for FPGA-SPICE */ /* Define the basic data structures used for FPGA-SPICE */
/* Default ID of switch used in rr_node */ /* Default ID of switch used in rr_node */
@ -135,3 +140,4 @@ struct fpga_spice_phy_pb {
int num_iopads; int num_iopads;
}; };
#endif

View File

@ -1,3 +1,6 @@
#ifndef ROUTE_COMMON_H
#define ROUTE_COMMON_H
/************ Defines and types shared by all route files ********************/ /************ Defines and types shared by all route files ********************/
typedef struct s_heap t_heap; typedef struct s_heap t_heap;
@ -118,4 +121,4 @@ void auto_detect_and_reserve_locally_used_opins(float pres_fac, boolean rip_up_l
void free_chunk_memory_trace(void); void free_chunk_memory_trace(void);
#endif