add node builder for tileable rr_graph builder

This commit is contained in:
tangxifan 2020-03-05 15:34:04 -07:00
parent 646ee90937
commit de62ce8872
8 changed files with 607 additions and 32 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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 |

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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