add node builder for tileable rr_graph builder
This commit is contained in:
parent
646ee90937
commit
de62ce8872
|
@ -117,6 +117,196 @@ size_t get_grid_num_classes(const t_grid_tile& cur_grid,
|
|||
return num_classes;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Idenfity if a X-direction routing channel exist in the fabric
|
||||
* This could be entirely possible that a routig channel
|
||||
* is in the middle of a multi-width and multi-height grid
|
||||
*
|
||||
* As the chanx always locates on top of a grid with the same coord
|
||||
*
|
||||
* +----------+
|
||||
* | CHANX |
|
||||
* | [x][y] |
|
||||
* +----------+
|
||||
*
|
||||
* +----------+
|
||||
* | Grid | height_offset = height - 1
|
||||
* | [x][y] |
|
||||
* +----------+
|
||||
*
|
||||
* +----------+
|
||||
* | Grid | height_offset = height - 2
|
||||
* | [x][y-1] |
|
||||
* +----------+
|
||||
* If the CHANX is in the middle of a multi-width and multi-height grid
|
||||
* it should locate at a grid whose height_offset is lower than the its height defined in physical_tile
|
||||
* When height_offset == height - 1, it means that the grid is at the top side of this multi-width and multi-height block
|
||||
***********************************************************************/
|
||||
bool is_chanx_exist(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord) {
|
||||
return (grids[chanx_coord.x()][chanx_coord.y()].height_offset == grids[chanx_coord.x()][chanx_coord.y()].type->height - 1);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Idenfity if a Y-direction routing channel exist in the fabric
|
||||
* This could be entirely possible that a routig channel
|
||||
* is in the middle of a multi-width and multi-height grid
|
||||
*
|
||||
* As the chany always locates on right of a grid with the same coord
|
||||
*
|
||||
* +-----------+ +---------+ +--------+
|
||||
* | Grid | | Grid | | CHANY |
|
||||
* | [x-1][y] | | [x][y] | | [x][y] |
|
||||
* +-----------+ +---------+ +--------+
|
||||
* width_offset width_offset
|
||||
* = width - 2 = width -1
|
||||
* If the CHANY is in the middle of a multi-width and multi-height grid
|
||||
* it should locate at a grid whose width_offset is lower than the its width defined in physical_tile
|
||||
* When height_offset == height - 1, it means that the grid is at the top side of this multi-width and multi-height block
|
||||
***********************************************************************/
|
||||
bool is_chany_exist(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord) {
|
||||
return (grids[chany_coord.x()][chany_coord.y()].width_offset == grids[chany_coord.y()][chany_coord.y()].type->width - 1);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Identify if a X-direction routing channel is at the right side of a
|
||||
* multi-height grid
|
||||
*
|
||||
* +-----------------+
|
||||
* | |
|
||||
* | | +-------------+
|
||||
* | Grid | | CHANX |
|
||||
* | [x-1][y] | | [x][y] |
|
||||
* | | +-------------+
|
||||
* | |
|
||||
* +-----------------+
|
||||
***********************************************************************/
|
||||
bool is_chanx_right_to_multi_height_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord) {
|
||||
VTR_ASSERT(0 < chanx_coord.x());
|
||||
if (1 == chanx_coord.x()) {
|
||||
/* This is already the LEFT side of FPGA fabric,
|
||||
* it is the same results as chanx is right to a multi-height grid
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We check the left neighbor of chanx, if it does not exist, the chanx is left to a multi-height grid */
|
||||
vtr::Point<size_t> left_chanx_coord(chanx_coord.x() - 1, chanx_coord.y());
|
||||
if (false == is_chanx_exist(grids, left_chanx_coord)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Identify if a X-direction routing channel is at the left side of a
|
||||
* multi-height grid
|
||||
*
|
||||
* +-----------------+
|
||||
* | |
|
||||
* +---------------+ | |
|
||||
* | CHANX | | Grid |
|
||||
* | [x][y] | | [x+1][y] |
|
||||
* +---------------+ | |
|
||||
* | |
|
||||
* +-----------------+
|
||||
***********************************************************************/
|
||||
bool is_chanx_left_to_multi_height_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord) {
|
||||
VTR_ASSERT(chanx_coord.x() < grids.width() - 1);
|
||||
if (grids.width() - 2 == chanx_coord.x()) {
|
||||
/* This is already the RIGHT side of FPGA fabric,
|
||||
* it is the same results as chanx is right to a multi-height grid
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We check the right neighbor of chanx, if it does not exist, the chanx is left to a multi-height grid */
|
||||
vtr::Point<size_t> right_chanx_coord(chanx_coord.x() + 1, chanx_coord.y());
|
||||
if (false == is_chanx_exist(grids, right_chanx_coord)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Identify if a Y-direction routing channel is at the top side of a
|
||||
* multi-width grid
|
||||
*
|
||||
* +--------+
|
||||
* | CHANY |
|
||||
* | [x][y] |
|
||||
* +--------+
|
||||
*
|
||||
* +-----------------+
|
||||
* | |
|
||||
* | |
|
||||
* | Grid |
|
||||
* | [x-1][y] |
|
||||
* | |
|
||||
* | |
|
||||
* +-----------------+
|
||||
***********************************************************************/
|
||||
bool is_chany_top_to_multi_width_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord) {
|
||||
VTR_ASSERT(0 < chany_coord.y());
|
||||
if (1 == chany_coord.y()) {
|
||||
/* This is already the BOTTOM side of FPGA fabric,
|
||||
* it is the same results as chany is at the top of a multi-width grid
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We check the bottom neighbor of chany, if it does not exist, the chany is left to a multi-height grid */
|
||||
vtr::Point<size_t> bottom_chany_coord(chany_coord.x(), chany_coord.y() - 1);
|
||||
if (false == is_chany_exist(grids, bottom_chany_coord)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Identify if a Y-direction routing channel is at the bottom side of a
|
||||
* multi-width grid
|
||||
*
|
||||
* +-----------------+
|
||||
* | |
|
||||
* | |
|
||||
* | Grid |
|
||||
* | [x+1][y] |
|
||||
* | |
|
||||
* | |
|
||||
* +-----------------+
|
||||
* +--------+
|
||||
* | CHANY |
|
||||
* | [x][y] |
|
||||
* +--------+
|
||||
*
|
||||
***********************************************************************/
|
||||
bool is_chany_bottom_to_multi_width_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord) {
|
||||
VTR_ASSERT(chany_coord.y() < grids.height() - 1);
|
||||
if (grids.height() - 2 == chany_coord.y()) {
|
||||
/* This is already the TOP side of FPGA fabric,
|
||||
* it is the same results as chany is at the bottom of a multi-width grid
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We check the top neighbor of chany, if it does not exist, the chany is left to a multi-height grid */
|
||||
vtr::Point<size_t> top_chany_coord(chany_coord.x(), chany_coord.y() + 1);
|
||||
if (false == is_chany_exist(grids, top_chany_coord)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Get the track_id of a routing track w.r.t its coordinator
|
||||
* In tileable routing architecture, the track_id changes SB by SB.
|
||||
|
|
|
@ -34,6 +34,24 @@ size_t get_grid_num_pins(const t_grid_tile& cur_grid,
|
|||
size_t get_grid_num_classes(const t_grid_tile& cur_grid,
|
||||
const e_pin_type& pin_type);
|
||||
|
||||
bool is_chanx_exist(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord);
|
||||
|
||||
bool is_chany_exist(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord);
|
||||
|
||||
bool is_chanx_right_to_multi_height_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord);
|
||||
|
||||
bool is_chanx_left_to_multi_height_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord);
|
||||
|
||||
bool is_chany_top_to_multi_width_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord);
|
||||
|
||||
bool is_chany_bottom_to_multi_width_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord);
|
||||
|
||||
short get_rr_node_actual_track_id(const RRGraph& rr_graph,
|
||||
const RRNodeId& track_rr_node,
|
||||
const vtr::Point<size_t>& coord,
|
||||
|
|
|
@ -19,11 +19,11 @@ namespace openfpga {
|
|||
* 2. A X-direction Connection block locates at the left side of the switch block
|
||||
* 2. A Y-direction Connection block locates at the top side of the switch block
|
||||
*
|
||||
* +---------------------------------+
|
||||
* | Y-direction CB |
|
||||
* | [x][y + 1] |
|
||||
* +---------------------------------+
|
||||
*
|
||||
* +-------------+ +---------------------------------+
|
||||
* | | | Y-direction CB |
|
||||
* | Grid | | [x][y + 1] |
|
||||
* | [x][y+1] | +---------------------------------+
|
||||
* +-------------+
|
||||
* TOP SIDE
|
||||
* +-------------+ +---------------------------------+
|
||||
* | | | OPIN_NODE CHAN_NODES OPIN_NODES |
|
||||
|
|
|
@ -161,8 +161,10 @@ int adapt_to_tileable_route_chan_width(const int& chan_width,
|
|||
* in X-direction and Y-direction channels!!!
|
||||
* So we will load segment details for different channels
|
||||
***********************************************************************/
|
||||
ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width, const size_t& max_seg_length,
|
||||
const enum e_side& device_side,
|
||||
ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width,
|
||||
const size_t& max_seg_length,
|
||||
const bool& force_start,
|
||||
const bool& force_end,
|
||||
const std::vector<t_segment_inf>& segment_inf) {
|
||||
ChanNodeDetails chan_node_details;
|
||||
size_t actual_chan_width = chan_width;
|
||||
|
@ -214,28 +216,20 @@ ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width, const s
|
|||
/* Check if all the tracks have been satisified */
|
||||
VTR_ASSERT(cur_track == actual_chan_width);
|
||||
|
||||
/* If this is on the border of a device, segments should start */
|
||||
switch (device_side) {
|
||||
case TOP:
|
||||
case RIGHT:
|
||||
/* INC_DIRECTION should all end */
|
||||
chan_node_details.set_tracks_end(INC_DIRECTION);
|
||||
/* DEC_DIRECTION should all start */
|
||||
chan_node_details.set_tracks_start(DEC_DIRECTION);
|
||||
break;
|
||||
case BOTTOM:
|
||||
case LEFT:
|
||||
/* If this is on the border of a device/heterogeneous blocks, segments should start/end */
|
||||
if (true == force_start) {
|
||||
/* INC_DIRECTION should all start */
|
||||
chan_node_details.set_tracks_start(INC_DIRECTION);
|
||||
/* DEC_DIRECTION should all end */
|
||||
chan_node_details.set_tracks_end(DEC_DIRECTION);
|
||||
break;
|
||||
case NUM_SIDES:
|
||||
break;
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid device_side!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* If this is on the border of a device/heterogeneous blocks, segments should start/end */
|
||||
if (true == force_end) {
|
||||
/* INC_DIRECTION should all end */
|
||||
chan_node_details.set_tracks_end(INC_DIRECTION);
|
||||
/* DEC_DIRECTION should all start */
|
||||
chan_node_details.set_tracks_start(DEC_DIRECTION);
|
||||
}
|
||||
|
||||
return chan_node_details;
|
||||
|
|
|
@ -17,8 +17,10 @@ namespace openfpga {
|
|||
|
||||
int adapt_to_tileable_route_chan_width(const int& chan_width, const std::vector<t_segment_inf>& segment_inf);
|
||||
|
||||
ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width, const size_t& max_seg_length,
|
||||
const e_side& device_side,
|
||||
ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width,
|
||||
const size_t& max_seg_length,
|
||||
const bool& force_start,
|
||||
const bool& force_end,
|
||||
const std::vector<t_segment_inf>& segment_inf);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -651,9 +651,9 @@ RRGSB build_one_tileable_rr_gsb(const DeviceGrid& grids,
|
|||
* We do not care starting and ending points here, so set chan_side as NUM_SIDES
|
||||
*/
|
||||
ChanNodeDetails chanx_details = build_unidir_chan_node_details(device_chan_width[0], grids.width() - 1,
|
||||
NUM_SIDES, segment_inf);
|
||||
false, false, segment_inf);
|
||||
ChanNodeDetails chany_details = build_unidir_chan_node_details(device_chan_width[1], grids.height() - 1,
|
||||
NUM_SIDES, segment_inf);
|
||||
false, false, segment_inf);
|
||||
|
||||
switch (side) {
|
||||
case TOP: /* TOP = 0 */
|
||||
|
|
|
@ -0,0 +1,340 @@
|
|||
/************************************************************************
|
||||
* This file contains functions that are used to allocate nodes
|
||||
* for the tileable routing resource graph builder
|
||||
***********************************************************************/
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
#include "vpr_utils.h"
|
||||
|
||||
#include "rr_graph_builder_utils.h"
|
||||
#include "tileable_chan_details_builder.h"
|
||||
#include "tileable_rr_graph_node_builder.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/************************************************************************
|
||||
* Find the number output pins by considering all the grid
|
||||
***********************************************************************/
|
||||
static
|
||||
size_t estimate_num_grid_rr_nodes_by_type(const DeviceGrid& grids,
|
||||
const t_rr_type& node_type) {
|
||||
size_t num_grid_rr_nodes = 0;
|
||||
|
||||
for (size_t ix = 0; ix < grids.width(); ++ix) {
|
||||
for (size_t iy = 0; iy < grids.height(); ++iy) {
|
||||
|
||||
/* Skip EMPTY tiles */
|
||||
if (true == is_empty_type(grids[ix][iy].type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip height > 1 or width > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ( (0 < grids[ix][iy].width_offset)
|
||||
|| (0 < grids[ix][iy].height_offset) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
enum e_side io_side = NUM_SIDES;
|
||||
|
||||
/* If this is the block on borders, we consider IO side */
|
||||
if (true == is_io_type(grids[ix][iy].type)) {
|
||||
vtr::Point<size_t> io_device_size(grids.width() - 1, grids.height() - 1);
|
||||
vtr::Point<size_t> grid_coordinate(ix, iy);
|
||||
io_side = determine_io_grid_pin_side(io_device_size, grid_coordinate);
|
||||
}
|
||||
|
||||
switch (node_type) {
|
||||
case OPIN:
|
||||
/* get the number of OPINs */
|
||||
num_grid_rr_nodes += get_grid_num_pins(grids[ix][iy], DRIVER, io_side);
|
||||
break;
|
||||
case IPIN:
|
||||
/* get the number of IPINs */
|
||||
num_grid_rr_nodes += get_grid_num_pins(grids[ix][iy], RECEIVER, io_side);
|
||||
break;
|
||||
case SOURCE:
|
||||
/* SOURCE: number of classes whose type is DRIVER */
|
||||
num_grid_rr_nodes += get_grid_num_classes(grids[ix][iy], DRIVER);
|
||||
break;
|
||||
case SINK:
|
||||
/* SINK: number of classes whose type is RECEIVER */
|
||||
num_grid_rr_nodes += get_grid_num_classes(grids[ix][iy], RECEIVER);
|
||||
break;
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid routing resource node!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num_grid_rr_nodes;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* For X-direction Channel: CHANX
|
||||
* We pair each x-direction routing channel to the grid below it
|
||||
* as they share the same coordinate
|
||||
*
|
||||
* As such, the range of CHANX coordinate starts from x = 1, y = 0
|
||||
* which is the grid (I/O) at the left bottom of the fabric
|
||||
*
|
||||
* As such, the range of CHANX coordinate ends to x = width - 2, y = height - 2
|
||||
* which is the grid at the top right of the core fabric
|
||||
* Note that the I/O ring is
|
||||
*
|
||||
* TOP SIDE OF FPGA
|
||||
*
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
* | Grid | | Grid | ... | Grid |
|
||||
* | [1][0] | | [2][0] | | [width-2][height-1] |
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
*
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
* | X-Channel | | X-Channel | ... | X-Channel |
|
||||
* | [1][0] | | [2][0] | | [width-2][height-2] |
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
*
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
* | Grid | | Grid | ... | Grid |
|
||||
* | [1][0] | | [2][0] | | [width-2][height-2] |
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
*
|
||||
* ... ... ...
|
||||
*
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
* | X-Channel | | X-Channel | ... | X-Channel |
|
||||
* | [1][1] | | [2][1] | | [width-2][1] |
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
*
|
||||
* LEFT +-------------+ +-------------+ +--------------+ RIGHT
|
||||
* SIDE | Grid | | Grid | ... | Grid | SIDE
|
||||
* GRID | [1][1] | | [2][1] | | [width-2][1] | GRID
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
*
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
* | X-Channel | | X-Channel | ... | X-Channel |
|
||||
* | [1][0] | | [2][0] | | [width-2][0] |
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
*
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
* | Grid | | Grid | ... | Grid |
|
||||
* | [1][0] | | [2][0] | | [width-2][0] |
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
*
|
||||
* BOTTOM SIDE OF FPGA
|
||||
*
|
||||
* The figure above describe how the X-direction routing channels are
|
||||
* organized in a homogeneous FPGA fabric
|
||||
* Note that we talk about general-purpose uni-directional routing architecture here
|
||||
* It means that a routing track may span across multiple grids
|
||||
* However, the hard limits are as follows
|
||||
* All the routing tracks will start at the most LEFT routing channel
|
||||
* All the routing tracks will end at the most RIGHT routing channel
|
||||
*
|
||||
* Things will become more complicated in terms of track starting and end
|
||||
* in the context of heterogeneous FPGAs
|
||||
* We may have a grid which span multiple column and rows, as exemplified in the figure below
|
||||
* In such case,
|
||||
* all the routing tracks [x-1][y] at the left side of the grid [x][y] are forced to end
|
||||
* all the routing tracks [x+2][y] at the right side of the grid [x][y] are forced to start
|
||||
* And there are no routing tracks inside the grid[x][y]
|
||||
* It means that X-channel [x][y] & [x+1][y] will no exist
|
||||
*
|
||||
* +------------+ +-------------+ +-------------+ +--------------+
|
||||
* | X-Channel | | X-Channel | | X-Channel | | X-Channel |
|
||||
* | [x-1][y+2] | | [x][y+2] | | [x+1][y+2] | | [x+2][y+2] |
|
||||
* +------------+ +-------------+ +-------------+ +--------------+
|
||||
*
|
||||
* +------------+ +-----------------------------------+ +--------------+
|
||||
* | Grid | | | | Grid |
|
||||
* | [x-1][y+1] | | | | [x+2][y+1] |
|
||||
* +------------+ | | +--------------+
|
||||
* | |
|
||||
* +------------+ | | +--------------+
|
||||
* | X-channel | | Grid | | X-Channel |
|
||||
* | [x-1][y] | | [x][y] - [x+1][y+1] | | [x+2][y] |
|
||||
* +------------+ | | +--------------+
|
||||
* | |
|
||||
* +------------+ | | +--------------+
|
||||
* | Grid | | | | Grid |
|
||||
* | [x-1][y] | | | | [x+2][y] |
|
||||
* +------------+ +-----------------------------------+ +--------------+
|
||||
*
|
||||
*
|
||||
*
|
||||
***********************************************************************/
|
||||
static
|
||||
size_t estimate_num_chanx_rr_nodes(const DeviceGrid& grids,
|
||||
const size_t& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs) {
|
||||
size_t num_chanx_rr_nodes = 0;
|
||||
|
||||
for (size_t iy = 0; iy < grids.height() - 1; ++iy) {
|
||||
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||
vtr::Point<size_t> chanx_coord(ix, iy);
|
||||
|
||||
/* Bypass if the routing channel does not exist */
|
||||
if (false == is_chanx_exist(grids, chanx_coord)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool force_start = false;
|
||||
bool force_end = false;
|
||||
|
||||
/* All the tracks have to start when
|
||||
* - the routing channel touch the RIGHT side a heterogeneous block
|
||||
* - the routing channel touch the LEFT side of FPGA
|
||||
*/
|
||||
if (true == is_chanx_right_to_multi_height_grid(grids, chanx_coord)) {
|
||||
force_start = true;
|
||||
}
|
||||
|
||||
/* All the tracks have to end when
|
||||
* - the routing channel touch the LEFT side a heterogeneous block
|
||||
* - the routing channel touch the RIGHT side of FPGA
|
||||
*/
|
||||
if (true == is_chanx_left_to_multi_height_grid(grids, chanx_coord)) {
|
||||
force_end = true;
|
||||
}
|
||||
|
||||
/* Evaluate if the routing channel locates in the middle of a grid */
|
||||
ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width, grids.width() - 2, force_start, force_end, segment_infs);
|
||||
/* When an INC_DIRECTION CHANX starts, we need a new rr_node */
|
||||
num_chanx_rr_nodes += chanx_details.get_num_starting_tracks(INC_DIRECTION);
|
||||
/* When an DEC_DIRECTION CHANX ends, we need a new rr_node */
|
||||
num_chanx_rr_nodes += chanx_details.get_num_ending_tracks(DEC_DIRECTION);
|
||||
}
|
||||
}
|
||||
|
||||
return num_chanx_rr_nodes;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Estimate the number of CHANY rr_nodes for Y-direction routing channels
|
||||
* The technical rationale is very similar to the X-direction routing channel
|
||||
* Refer to the detailed explanation there
|
||||
***********************************************************************/
|
||||
static
|
||||
size_t estimate_num_chany_rr_nodes(const DeviceGrid& grids,
|
||||
const size_t& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs) {
|
||||
size_t num_chany_rr_nodes = 0;
|
||||
|
||||
for (size_t ix = 0; ix < grids.width() - 1; ++ix) {
|
||||
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||
vtr::Point<size_t> chany_coord(ix, iy);
|
||||
|
||||
/* Bypass if the routing channel does not exist */
|
||||
if (false == is_chany_exist(grids, chany_coord)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool force_start = false;
|
||||
bool force_end = false;
|
||||
|
||||
/* All the tracks have to start when
|
||||
* - the routing channel touch the TOP side a heterogeneous block
|
||||
* - the routing channel touch the BOTTOM side of FPGA
|
||||
*/
|
||||
if (true == is_chany_top_to_multi_width_grid(grids, chany_coord)) {
|
||||
force_start = true;
|
||||
}
|
||||
|
||||
/* All the tracks have to end when
|
||||
* - the routing channel touch the BOTTOM side a heterogeneous block
|
||||
* - the routing channel touch the TOP side of FPGA
|
||||
*/
|
||||
if (true == is_chany_bottom_to_multi_width_grid(grids, chany_coord)) {
|
||||
force_end = true;
|
||||
}
|
||||
|
||||
ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width, grids.height() - 2, force_start, force_end, segment_infs);
|
||||
/* When an INC_DIRECTION CHANX starts, we need a new rr_node */
|
||||
num_chany_rr_nodes += chany_details.get_num_starting_tracks(INC_DIRECTION);
|
||||
/* When an DEC_DIRECTION CHANX ends, we need a new rr_node */
|
||||
num_chany_rr_nodes += chany_details.get_num_ending_tracks(DEC_DIRECTION);
|
||||
}
|
||||
}
|
||||
|
||||
return num_chany_rr_nodes;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Estimate the number of nodes by each type in a routing resource graph
|
||||
***********************************************************************/
|
||||
static
|
||||
std::vector<size_t> estimate_num_rr_nodes(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs) {
|
||||
|
||||
/* Reset the OPIN, IPIN, SOURCE, SINK counter to be zero */
|
||||
std::vector<size_t> num_rr_nodes_per_type(NUM_RR_TYPES, 0);
|
||||
|
||||
/**
|
||||
* 1 Find number of rr nodes related to grids
|
||||
*/
|
||||
num_rr_nodes_per_type[OPIN] = estimate_num_grid_rr_nodes_by_type(grids, OPIN);
|
||||
num_rr_nodes_per_type[IPIN] = estimate_num_grid_rr_nodes_by_type(grids, IPIN);
|
||||
num_rr_nodes_per_type[SOURCE] = estimate_num_grid_rr_nodes_by_type(grids, SOURCE);
|
||||
num_rr_nodes_per_type[SINK] = estimate_num_grid_rr_nodes_by_type(grids, SINK);
|
||||
|
||||
/**
|
||||
* 2. Assign the segments for each routing channel,
|
||||
* To be specific, for each routing track, we assign a routing segment.
|
||||
* The assignment is subject to users' specifications, such as
|
||||
* a. length of each type of segment
|
||||
* b. frequency of each type of segment.
|
||||
* c. routing channel width
|
||||
*
|
||||
* SPECIAL for fringes:
|
||||
* All segments will start and ends with no exception
|
||||
*
|
||||
* IMPORTANT: we should be aware that channel width maybe different
|
||||
* in X-direction and Y-direction channels!!!
|
||||
* So we will load segment details for different channels
|
||||
*/
|
||||
num_rr_nodes_per_type[CHANX] = estimate_num_chanx_rr_nodes(grids, chan_width.x(), segment_infs);
|
||||
num_rr_nodes_per_type[CHANY] = estimate_num_chany_rr_nodes(grids, chan_width.y(), segment_infs);
|
||||
|
||||
return num_rr_nodes_per_type;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Allocate rr_nodes to a rr_graph object
|
||||
* This function just allocate the memory and ensure its efficiency
|
||||
* It will NOT fill detailed information for each node!!!
|
||||
*
|
||||
* Note: ensure that there are NO nodes in the rr_graph
|
||||
***********************************************************************/
|
||||
void alloc_rr_graph_nodes(RRGraph& rr_graph,
|
||||
const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs) {
|
||||
VTR_ASSERT(0 == rr_graph.nodes().size());
|
||||
|
||||
std::vector<size_t> num_rr_nodes_per_type = estimate_num_rr_nodes(grids, chan_width, segment_infs);
|
||||
|
||||
/* Reserve the number of node to be memory efficient */
|
||||
size_t num_nodes = 0;
|
||||
for (const size_t& num_node_per_type : num_rr_nodes_per_type) {
|
||||
num_nodes += num_node_per_type;
|
||||
}
|
||||
|
||||
rr_graph.reserve_nodes(num_nodes);
|
||||
|
||||
/* Add nodes by types */
|
||||
for (const t_rr_type& node_type : {SOURCE, SINK, IPIN, OPIN, CHANX, CHANY}) {
|
||||
for (size_t inode = 0; inode < num_rr_nodes_per_type[size_t(node_type)]; ++inode) {
|
||||
rr_graph.create_node(node_type);
|
||||
}
|
||||
}
|
||||
|
||||
VTR_ASSERT(num_nodes == rr_graph.nodes().size());
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef TILEABLE_RR_GRAPH_NODE_BUILDER_H
|
||||
#define TILEABLE_RR_GRAPH_NODE_BUILDER_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
/* Headers from readarch library */
|
||||
#include "physical_types.h"
|
||||
|
||||
/* Headers from vpr library */
|
||||
#include "rr_graph_obj.h"
|
||||
#include "device_grid.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void alloc_rr_graph_nodes(RRGraph& rr_graph,
|
||||
const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue