keep developing tileable rr_graph, track2ipin and opin2track to go
This commit is contained in:
parent
ba15358564
commit
2f15d2d13c
|
@ -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 */
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue