From 850788eacea0934cbfa7ec2e3f983e6b482c335b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 5 Mar 2020 17:15:49 -0700 Subject: [PATCH 1/2] adapt tileable rr_graph node builder for rr_graph object --- .../tileable_rr_graph_node_builder.cpp | 330 +++++++++++++++++- .../tileable_rr_graph_node_builder.h | 15 +- 2 files changed, 332 insertions(+), 13 deletions(-) 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 index c8dbe38b1..34347befc 100644 --- a/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp @@ -7,8 +7,14 @@ #include "vtr_log.h" #include "vtr_geometry.h" +/* Headers from openfpgautil library */ +#include "openfpga_side_manager.h" + +#include "vpr_types.h" #include "vpr_utils.h" +#include "rr_node.h" + #include "rr_graph_builder_utils.h" #include "tileable_chan_details_builder.h" #include "tileable_rr_graph_node_builder.h" @@ -311,10 +317,11 @@ std::vector estimate_num_rr_nodes(const DeviceGrid& grids, * * 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) { +void alloc_tileable_rr_graph_nodes(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + 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); @@ -327,14 +334,319 @@ void alloc_rr_graph_nodes(RRGraph& rr_graph, 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); + rr_node_driver_switches.reserve(num_nodes); +} + +/************************************************************************ + * Configure OPIN rr_nodes for this grid + * coordinates: xlow, ylow, xhigh, yhigh, + * features: capacity, ptc_num (pin_num), + * + * Note: this function should be applied ONLY to grid with 0 width offset and 0 height offset!!! + ***********************************************************************/ +static +void load_one_grid_opin_nodes_basic_info(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + const vtr::Point& grid_coordinate, + const t_grid_tile& cur_grid, + const e_side& io_side, + const RRSwitchId& delayless_switch) { + SideManager io_side_manager(io_side); + + /* Walk through the width height of each grid, + * get pins and configure the rr_nodes + */ + for (int width = 0; width < cur_grid.type->width; ++width) { + for (int height = 0; height < cur_grid.type->height; ++height) { + /* Walk through sides */ + for (size_t side = 0; side < NUM_SIDES; ++side) { + SideManager side_manager(side); + /* skip unwanted sides */ + if ( (true == is_io_type(cur_grid.type)) + && (side != io_side_manager.to_size_t()) ) { + continue; + } + /* Find OPINs */ + /* Configure pins by pins */ + std::vector opin_list = get_grid_side_pins(cur_grid, DRIVER, side_manager.get_side(), + width, height); + for (const int& pin_num : opin_list) { + /* Create a new node and fill information */ + const RRNodeId& node = rr_graph.create_node(OPIN); + + /* node bounding box */ + rr_graph.set_node_bounding_box(node, vtr::Rect(grid_coordinate.x() + width, + grid_coordinate.x() + width, + grid_coordinate.y() + height, + grid_coordinate.y() + height)); + rr_graph.set_node_side(node, side_manager.get_side()); + rr_graph.set_node_pin_num(node, pin_num); + + rr_graph.set_node_capacity(node, 1); + + /* cost index is a FIXED value for OPIN */ + rr_graph.set_node_cost_index(node, OPIN_COST_INDEX); + + /* Switch info */ + VTR_ASSERT(size_t(node) == rr_node_driver_switches.size()); + rr_node_driver_switches.push_back(delayless_switch); + + /* RC data */ + rr_graph.set_node_rc_data_index(node, find_create_rr_rc_data(0., 0.)); + + } /* End of loading OPIN rr_nodes */ + } /* End of side enumeration */ + } /* End of height enumeration */ + } /* End of width enumeration */ +} + +/************************************************************************ + * Configure IPIN rr_nodes for this grid + * coordinates: xlow, ylow, xhigh, yhigh, + * features: capacity, ptc_num (pin_num), + * + * Note: this function should be applied ONLY to grid with 0 width offset and 0 height offset!!! + ***********************************************************************/ +static +void load_one_grid_ipin_nodes_basic_info(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + const vtr::Point& grid_coordinate, + const t_grid_tile& cur_grid, + const e_side& io_side, + const RRSwitchId& wire_to_ipin_switch) { + SideManager io_side_manager(io_side); + + /* Walk through the width and height of each grid, + * get pins and configure the rr_nodes + */ + for (int width = 0; width < cur_grid.type->width; ++width) { + for (int height = 0; height < cur_grid.type->height; ++height) { + /* Walk through sides */ + for (size_t side = 0; side < NUM_SIDES; ++side) { + SideManager side_manager(side); + /* skip unwanted sides */ + if ( (true == is_io_type(cur_grid.type)) + && (side != io_side_manager.to_size_t()) ) { + continue; + } + + /* Find IPINs */ + /* Configure pins by pins */ + std::vector ipin_list = get_grid_side_pins(cur_grid, RECEIVER, side_manager.get_side(), width, height); + for (const int& pin_num : ipin_list) { + /* Create a new node and fill information */ + const RRNodeId& node = rr_graph.create_node(IPIN); + + /* node bounding box */ + rr_graph.set_node_bounding_box(node, vtr::Rect(grid_coordinate.x() + width, + grid_coordinate.x() + width, + grid_coordinate.y() + height, + grid_coordinate.y() + height)); + rr_graph.set_node_side(node, side_manager.get_side()); + rr_graph.set_node_pin_num(node, pin_num); + + rr_graph.set_node_capacity(node, 1); + + /* cost index is a FIXED value for OPIN */ + rr_graph.set_node_cost_index(node, IPIN_COST_INDEX); + + /* Switch info */ + VTR_ASSERT(size_t(node) == rr_node_driver_switches.size()); + rr_node_driver_switches.push_back(wire_to_ipin_switch); + + /* RC data */ + rr_graph.set_node_rc_data_index(node, find_create_rr_rc_data(0., 0.)); + + } /* End of loading IPIN rr_nodes */ + } /* End of side enumeration */ + } /* End of height enumeration */ + } /* End of width enumeration */ +} + +/************************************************************************ + * Configure SOURCE rr_nodes for this grid + * coordinates: xlow, ylow, xhigh, yhigh, + * features: capacity, ptc_num (pin_num), + * + * Note: this function should be applied ONLY to grid with 0 width offset and 0 height offset!!! + ***********************************************************************/ +static +void load_one_grid_source_nodes_basic_info(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + const vtr::Point& grid_coordinate, + const t_grid_tile& cur_grid, + const e_side& io_side, + const RRSwitchId& delayless_switch) { + SideManager io_side_manager(io_side); + + /* Set a SOURCE rr_node for each DRIVER class */ + for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) { + /* Set a SINK rr_node for the OPIN */ + if (DRIVER != cur_grid.type->class_inf[iclass].type) { + continue; + } + + /* Create a new node and fill information */ + const RRNodeId& node = rr_graph.create_node(SOURCE); + + /* node bounding box */ + rr_graph.set_node_bounding_box(node, vtr::Rect(grid_coordinate.x(), + grid_coordinate.x(), + grid_coordinate.y(), + grid_coordinate.y())); + rr_graph.set_node_class_num(node, iclass); + + rr_graph.set_node_capacity(node, 1); + + /* The capacity should be the number of pins in this class*/ + rr_graph.set_node_capacity(node, cur_grid.type->class_inf[iclass].num_pins); + + /* cost index is a FIXED value for SOURCE */ + rr_graph.set_node_cost_index(node, SOURCE_COST_INDEX); + + /* Switch info */ + VTR_ASSERT(size_t(node) == rr_node_driver_switches.size()); + rr_node_driver_switches.push_back(delayless_switch); + + /* RC data */ + rr_graph.set_node_rc_data_index(node, find_create_rr_rc_data(0., 0.)); + + } /* End of class enumeration */ +} + +/************************************************************************ + * Configure SINK rr_nodes for this grid + * coordinates: xlow, ylow, xhigh, yhigh, + * features: capacity, ptc_num (pin_num), + * + * Note: this function should be applied ONLY to grid with 0 width offset and 0 height offset!!! + ***********************************************************************/ +static +void load_one_grid_sink_nodes_basic_info(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + const vtr::Point& grid_coordinate, + const t_grid_tile& cur_grid, + const e_side& io_side, + const RRSwitchId& delayless_switch) { + SideManager io_side_manager(io_side); + + /* Set a SINK rr_node for each RECEIVER class */ + for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) { + /* Set a SINK rr_node for the OPIN */ + if (RECEIVER != cur_grid.type->class_inf[iclass].type) { + continue; + } + + /* Create a new node and fill information */ + const RRNodeId& node = rr_graph.create_node(SINK); + + /* node bounding box */ + rr_graph.set_node_bounding_box(node, vtr::Rect(grid_coordinate.x(), + grid_coordinate.x(), + grid_coordinate.y(), + grid_coordinate.y())); + rr_graph.set_node_class_num(node, iclass); + + rr_graph.set_node_capacity(node, 1); + + /* The capacity should be the number of pins in this class*/ + rr_graph.set_node_capacity(node, cur_grid.type->class_inf[iclass].num_pins); + + /* cost index is a FIXED value for SINK */ + rr_graph.set_node_cost_index(node, SINK_COST_INDEX); + + /* Switch info */ + VTR_ASSERT(size_t(node) == rr_node_driver_switches.size()); + rr_node_driver_switches.push_back(delayless_switch); + + /* RC data */ + rr_graph.set_node_rc_data_index(node, find_create_rr_rc_data(0., 0.)); + + } /* End of class enumeration */ +} + +/************************************************************************ + * Create all the rr_nodes for grids + ***********************************************************************/ +static +void load_grid_nodes_basic_info(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + const DeviceGrid& grids, + const RRSwitchId& wire_to_ipin_switch, + const RRSwitchId& delayless_switch) { + + for (size_t iy = 0; iy < grids.height(); ++iy) { + for (size_t ix = 0; ix < grids.width(); ++ix) { + /* Skip EMPTY tiles */ + if (true == is_empty_type(grids[ix][iy].type)) { + continue; + } + + /* We only build rr_nodes for grids with width_offset = 0 and height_offset = 0 */ + if ( (0 < grids[ix][iy].width_offset) + || (0 < grids[ix][iy].height_offset) ) { + continue; + } + + vtr::Point grid_coordinate(ix, iy); + 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); + io_side = determine_io_grid_pin_side(io_device_size, grid_coordinate); + } + + /* Configure source rr_nodes for this grid */ + load_one_grid_source_nodes_basic_info(rr_graph, + rr_node_driver_switches, + grid_coordinate, + grids[ix][iy], + io_side, + delayless_switch); + + /* Configure sink rr_nodes for this grid */ + load_one_grid_sink_nodes_basic_info(rr_graph, + rr_node_driver_switches, + grid_coordinate, + grids[ix][iy], + io_side, + delayless_switch); + + /* Configure opin rr_nodes for this grid */ + load_one_grid_opin_nodes_basic_info(rr_graph, + rr_node_driver_switches, + grid_coordinate, + grids[ix][iy], + io_side, + delayless_switch); + + /* Configure ipin rr_nodes for this grid */ + load_one_grid_ipin_nodes_basic_info(rr_graph, + rr_node_driver_switches, + grid_coordinate, + grids[ix][iy], + io_side, + wire_to_ipin_switch); + } } +} + +/************************************************************************ + * Create all the rr_nodes covering both grids and routing channels + ***********************************************************************/ +void create_tileable_rr_graph_nodes(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + const DeviceGrid& grids, + const RRSwitchId& wire_to_ipin_switch, + const RRSwitchId& delayless_switch) { + load_grid_nodes_basic_info(rr_graph, + rr_node_driver_switches, + grids, + wire_to_ipin_switch, + delayless_switch); - 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 index a263324fe..7cd8c673a 100644 --- a/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.h +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.h @@ -21,10 +21,17 @@ /* 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); +void alloc_tileable_rr_graph_nodes(RRGraph& rr_graph, + vtr::vector& driver_switches, + const DeviceGrid& grids, + const vtr::Point& chan_width, + const std::vector& segment_infs); + +void create_tileable_rr_graph_nodes(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + const DeviceGrid& grids, + const RRSwitchId& wire_to_ipin_switch, + const RRSwitchId& delayless_switch); } /* end namespace openfpga */ From 5067dd846e8919754fe41d55a78ce3fbd482c2ef Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 5 Mar 2020 17:47:48 -0700 Subject: [PATCH 2/2] adapting channel rr_node builder for tileable rr_graph --- .../tileable_rr_graph/chan_node_details.cpp | 33 +++--- .../tileable_rr_graph_node_builder.cpp | 105 ++++++++++++++++++ 2 files changed, 123 insertions(+), 15 deletions(-) diff --git a/vpr/src/tileable_rr_graph/chan_node_details.cpp b/vpr/src/tileable_rr_graph/chan_node_details.cpp index f52188d93..ef2df157e 100644 --- a/vpr/src/tileable_rr_graph/chan_node_details.cpp +++ b/vpr/src/tileable_rr_graph/chan_node_details.cpp @@ -1,8 +1,11 @@ /************************************************************************ * This file contains member functions for class ChanNodeDetails ***********************************************************************/ -#include #include + +/* Headers from vtrutil library */ +#include "vtr_assert.h" + #include "chan_node_details.h" /* begin namespace openfpga */ @@ -33,12 +36,12 @@ ChanNodeDetails::ChanNodeDetails() { * Accessors ***********************************************************************/ size_t ChanNodeDetails::get_chan_width() const { - assert(validate_chan_width()); + VTR_ASSERT(validate_chan_width()); return track_node_ids_.size(); } size_t ChanNodeDetails::get_track_node_id(const size_t& track_id) const { - assert(validate_track_id(track_id)); + VTR_ASSERT(validate_track_id(track_id)); return track_node_ids_[track_id]; } @@ -52,27 +55,27 @@ std::vector ChanNodeDetails::get_track_node_ids() const { } e_direction ChanNodeDetails::get_track_direction(const size_t& track_id) const { - assert(validate_track_id(track_id)); + VTR_ASSERT(validate_track_id(track_id)); return track_direction_[track_id]; } size_t ChanNodeDetails::get_track_segment_length(const size_t& track_id) const { - assert(validate_track_id(track_id)); + VTR_ASSERT(validate_track_id(track_id)); return seg_length_[track_id]; } size_t ChanNodeDetails::get_track_segment_id(const size_t& track_id) const { - assert(validate_track_id(track_id)); + VTR_ASSERT(validate_track_id(track_id)); return seg_ids_[track_id]; } bool ChanNodeDetails::is_track_start(const size_t& track_id) const { - assert(validate_track_id(track_id)); + VTR_ASSERT(validate_track_id(track_id)); return track_start_[track_id]; } bool ChanNodeDetails::is_track_end(const size_t& track_id) const { - assert(validate_track_id(track_id)); + VTR_ASSERT(validate_track_id(track_id)); return track_end_[track_id]; } @@ -81,9 +84,9 @@ bool ChanNodeDetails::is_track_end(const size_t& track_id) const { * A group size is the number of such nodes between the starting points (include the 1st starting point) */ std::vector ChanNodeDetails::get_seg_group(const size_t& track_id) const { - assert(validate_chan_width()); - assert(validate_track_id(track_id)); - assert(is_track_start(track_id)); + VTR_ASSERT(validate_chan_width()); + VTR_ASSERT(validate_track_id(track_id)); + VTR_ASSERT(is_track_start(track_id)); std::vector group; /* Make sure a clean start */ @@ -115,7 +118,7 @@ std::vector ChanNodeDetails::get_seg_group_node_id(const std::vector& track_node_ids) { /* the size of vector should match chan_width */ - assert ( get_chan_width() == track_node_ids.size() ); + VTR_ASSERT ( get_chan_width() == track_node_ids.size() ); for (size_t inode = 0; inode < track_node_ids.size(); ++inode) { track_node_ids_[inode] = track_node_ids[inode]; } @@ -227,7 +230,7 @@ void ChanNodeDetails::rotate_track_node_id(const size_t& offset, const e_directi /* Rotate the node_ids by groups * A group begins from a track_start and ends before another track_start */ - assert(validate_chan_width()); + VTR_ASSERT(validate_chan_width()); for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) { /* Bypass non-start segment */ if (false == is_track_start(itrack) ) { 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 index 34347befc..0ea35af13 100644 --- a/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp @@ -633,6 +633,111 @@ void load_grid_nodes_basic_info(RRGraph& rr_graph, } } +/************************************************************************ + * Initialize the basic information of routing track rr_nodes + * coordinates: xlow, ylow, xhigh, yhigh, + * features: capacity, track_ids, ptc_num, direction + ***********************************************************************/ +static +void load_one_chan_rr_nodes_basic_info(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + std::map>& rr_node_track_ids, + const vtr::Point& chan_coordinate, + const t_rr_type& chan_type, + ChanNodeDetails& chan_details, + const std::vector& segment_infs, + const int& cost_index_offset) { + /* Check each node_id(potential ptc_num) in the channel : + * If this is a starting point, we set a new rr_node with xlow/ylow, ptc_num + * If this is a ending point, we set xhigh/yhigh and track_ids + * For other nodes, we set changes in track_ids + */ + for (size_t itrack = 0; itrack < chan_details.get_chan_width(); ++itrack) { + /* For INC direction, a starting point requires a new chan rr_node */ + if ( ( (true == chan_details.is_track_start(itrack)) + && (INC_DIRECTION == chan_details.get_track_direction(itrack)) ) + /* For DEC direction, an ending point requires a new chan rr_node */ + || + ( (true == chan_details.is_track_end(itrack)) + && (DEC_DIRECTION == chan_details.get_track_direction(itrack)) ) ) { + + /* Create a new chan rr_node */ + const RRNodeId& node = rr_graph.create_node(chan_type); + + rr_graph.set_node_xlow(node, chan_coordinate.x()); + rr_graph.set_node_ylow(node, chan_coordinate.y()); + + rr_graph.set_node_direction(node, chan_details.get_track_direction(itrack)); + rr_graph.set_node_track_num(node, itrack); + rr_node_track_ids[node].push_back(itrack); + + rr_graph.set_node_capacity(node, 1); + + /* assign switch id */ + size_t seg_id = chan_details.get_track_segment_id(itrack); + VTR_ASSERT(size_t(node) == rr_node_driver_switches.size()); + rr_node_driver_switches.push_back(RRSwitchId(segment_infs[seg_id].arch_opin_switch)); + + /* Update chan_details with node_id */ + chan_details.set_track_node_id(itrack, size_t(node)); + + /* cost index depends on the segment index */ + rr_graph.set_node_cost_index(node, cost_index_offset + seg_id); + /* Finish here, go to next */ + } + + /* For INC direction, an ending point requires an update on xhigh and yhigh */ + if ( ( (true == chan_details.is_track_end(itrack)) + && (INC_DIRECTION == chan_details.get_track_direction(itrack)) ) + || + /* For DEC direction, an starting point requires an update on xlow and ylow */ + ( (true == chan_details.is_track_start(itrack)) + && (DEC_DIRECTION == chan_details.get_track_direction(itrack)) ) ) { + + /* Get the node_id */ + const RRNodeId& rr_node_id = RRNodeId(chan_details.get_track_node_id(itrack)); + + /* Do a quick check, make sure we do not mistakenly modify other nodes */ + VTR_ASSERT(chan_type == rr_graph.node_type(rr_node_id)); + VTR_ASSERT(chan_details.get_track_direction(itrack) == rr_graph.node_direction(rr_node_id)); + + /* set xhigh/yhigh and push changes to track_ids */ + rr_graph.set_node_xhigh(rr_node_id, chan_coordinate.x()); + rr_graph.set_node_yhigh(rr_node_id, chan_coordinate.y()); + + /* Do not update track_ids for length-1 wires, they should have only 1 track_id */ + if ( (rr_graph.node_xhigh(rr_node_id) > rr_graph.node_xlow(rr_node_id)) + || (rr_graph.node_yhigh(rr_node_id) > rr_graph.node_ylow(rr_node_id)) ) { + rr_node_track_ids[rr_node_id].push_back(itrack); + } + /* Finish here, go to next */ + } + + /* Finish processing starting and ending tracks */ + if ( (true == chan_details.is_track_start(itrack)) + || (true == chan_details.is_track_end(itrack)) ) { + /* Finish here, go to next */ + continue; + } + + /* For other nodes, we get the node_id and just update track_ids */ + /* Ensure those nodes are neither starting nor ending points */ + VTR_ASSERT( (false == chan_details.is_track_start(itrack)) + && (false == chan_details.is_track_end(itrack)) ); + + /* Get the node_id */ + const RRNodeId& rr_node_id = RRNodeId(chan_details.get_track_node_id(itrack)); + + /* Do a quick check, make sure we do not mistakenly modify other nodes */ + VTR_ASSERT(chan_type == rr_graph.node_type(rr_node_id)); + VTR_ASSERT(chan_details.get_track_direction(itrack) == rr_graph.node_direction(rr_node_id)); + + /* Update track_ids */ + rr_node_track_ids[rr_node_id].push_back(itrack); + /* Finish here, go to next */ + } +} + /************************************************************************ * Create all the rr_nodes covering both grids and routing channels ***********************************************************************/