From de62ce8872757347c2e05dc905aa8843e392fd60 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 5 Mar 2020 15:34:04 -0700 Subject: [PATCH] add node builder for tileable rr_graph builder --- .../rr_graph_builder_utils.cpp | 190 ++++++++++ .../rr_graph_builder_utils.h | 18 + vpr/src/tileable_rr_graph/rr_gsb.h | 10 +- .../tileable_chan_details_builder.cpp | 40 +-- .../tileable_chan_details_builder.h | 6 +- .../tileable_rr_graph_gsb.cpp | 4 +- .../tileable_rr_graph_node_builder.cpp | 340 ++++++++++++++++++ .../tileable_rr_graph_node_builder.h | 31 ++ 8 files changed, 607 insertions(+), 32 deletions(-) create mode 100644 vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp create mode 100644 vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.h diff --git a/vpr/src/tileable_rr_graph/rr_graph_builder_utils.cpp b/vpr/src/tileable_rr_graph/rr_graph_builder_utils.cpp index 209d8a80b..47926e8c7 100644 --- a/vpr/src/tileable_rr_graph/rr_graph_builder_utils.cpp +++ b/vpr/src/tileable_rr_graph/rr_graph_builder_utils.cpp @@ -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& 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& 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& 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 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& 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 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& 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 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& 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 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. diff --git a/vpr/src/tileable_rr_graph/rr_graph_builder_utils.h b/vpr/src/tileable_rr_graph/rr_graph_builder_utils.h index f67acb038..1367466d4 100644 --- a/vpr/src/tileable_rr_graph/rr_graph_builder_utils.h +++ b/vpr/src/tileable_rr_graph/rr_graph_builder_utils.h @@ -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& chanx_coord); + +bool is_chany_exist(const DeviceGrid& grids, + const vtr::Point& chany_coord); + +bool is_chanx_right_to_multi_height_grid(const DeviceGrid& grids, + const vtr::Point& chanx_coord); + +bool is_chanx_left_to_multi_height_grid(const DeviceGrid& grids, + const vtr::Point& chanx_coord); + +bool is_chany_top_to_multi_width_grid(const DeviceGrid& grids, + const vtr::Point& chany_coord); + +bool is_chany_bottom_to_multi_width_grid(const DeviceGrid& grids, + const vtr::Point& chany_coord); + short get_rr_node_actual_track_id(const RRGraph& rr_graph, const RRNodeId& track_rr_node, const vtr::Point& coord, diff --git a/vpr/src/tileable_rr_graph/rr_gsb.h b/vpr/src/tileable_rr_graph/rr_gsb.h index f582d7ce3..8d729139a 100644 --- a/vpr/src/tileable_rr_graph/rr_gsb.h +++ b/vpr/src/tileable_rr_graph/rr_gsb.h @@ -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 | diff --git a/vpr/src/tileable_rr_graph/tileable_chan_details_builder.cpp b/vpr/src/tileable_rr_graph/tileable_chan_details_builder.cpp index 5259c9445..23c1d7c07 100644 --- a/vpr/src/tileable_rr_graph/tileable_chan_details_builder.cpp +++ b/vpr/src/tileable_rr_graph/tileable_chan_details_builder.cpp @@ -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& segment_inf) { ChanNodeDetails chan_node_details; size_t actual_chan_width = chan_width; @@ -180,7 +182,7 @@ ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width, const s } /* Find the number of segments required by each group */ - std::vector num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, false); + std::vector num_tracks = get_num_tracks_per_seg_type(actual_chan_width / 2, segment_inf, false); /* Add node to ChanNodeDetails */ size_t cur_track = 0; @@ -188,7 +190,7 @@ ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width, const s /* segment length will be set to maxium segment length if this is a longwire */ size_t seg_len = segment_inf[iseg].length; if (true == segment_inf[iseg].longline) { - seg_len = max_seg_length; + seg_len = max_seg_length; } for (size_t itrack = 0; itrack < num_tracks[iseg]; ++itrack) { bool seg_start = false; @@ -213,29 +215,21 @@ 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; diff --git a/vpr/src/tileable_rr_graph/tileable_chan_details_builder.h b/vpr/src/tileable_rr_graph/tileable_chan_details_builder.h index cc111541f..b1a1198b9 100644 --- a/vpr/src/tileable_rr_graph/tileable_chan_details_builder.h +++ b/vpr/src/tileable_rr_graph/tileable_chan_details_builder.h @@ -17,8 +17,10 @@ namespace openfpga { int adapt_to_tileable_route_chan_width(const int& chan_width, const std::vector& 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& segment_inf); } /* end namespace openfpga */ diff --git a/vpr/src/tileable_rr_graph/tileable_rr_graph_gsb.cpp b/vpr/src/tileable_rr_graph/tileable_rr_graph_gsb.cpp index 332a44e94..9cbc69dff 100755 --- a/vpr/src/tileable_rr_graph/tileable_rr_graph_gsb.cpp +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_gsb.cpp @@ -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 */ diff --git a/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp b/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp new file mode 100644 index 000000000..c8dbe38b1 --- /dev/null +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp @@ -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 io_device_size(grids.width() - 1, grids.height() - 1); + vtr::Point 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& 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 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& 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 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 estimate_num_rr_nodes(const DeviceGrid& grids, + const vtr::Point& chan_width, + const std::vector& segment_infs) { + + /* Reset the OPIN, IPIN, SOURCE, SINK counter to be zero */ + std::vector 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& chan_width, + const std::vector& segment_infs) { + VTR_ASSERT(0 == rr_graph.nodes().size()); + + std::vector 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 */ diff --git a/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.h b/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.h new file mode 100644 index 000000000..a263324fe --- /dev/null +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.h @@ -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& chan_width, + const std::vector& segment_infs); + +} /* end namespace openfpga */ + +#endif