From 328488f357190e598c44f926d46839ce175d25e6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 5 Mar 2020 20:15:16 -0700 Subject: [PATCH 1/2] adapt chan rr node builder to use rr_graph obj --- .../tileable_rr_graph_node_builder.cpp | 227 ++++++++++++++++++ .../tileable_rr_graph_node_builder.h | 4 + 2 files changed, 231 insertions(+) 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 0ea35af13..2928ed335 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 @@ -738,12 +738,222 @@ void load_one_chan_rr_nodes_basic_info(RRGraph& rr_graph, } } +/************************************************************************ + * Initialize the basic information of X-channel rr_nodes: + * coordinates: xlow, ylow, xhigh, yhigh, + * features: capacity, track_ids, ptc_num, direction + * grid_info : pb_graph_pin + ***********************************************************************/ +static +void load_chanx_rr_nodes_basic_info(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + std::map>& rr_node_track_ids, + const DeviceGrid& grids, + const size_t& chan_width, + const std::vector& segment_infs) { + + /* For X-direction Channel: CHANX */ + for (size_t iy = 0; iy < grids.height() - 1; ++iy) { + /* Keep a vector of node_ids for the channels, because we will rotate them when walking through ix */ + std::vector track_node_ids; + + 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; + } + + ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width, grids.width() - 2, + force_start, force_end, segment_infs); + /* Force node_ids from the previous chanx */ + if (0 < track_node_ids.size()) { + /* Rotate should be done based on a typical case of routing tracks. + * Tracks on the borders are not regularly started and ended, + * which causes the node_rotation malfunction + */ + ChanNodeDetails chanx_details_tt = build_unidir_chan_node_details(chan_width, grids.width() - 2, + false, false, segment_infs); + chanx_details_tt.set_track_node_ids(track_node_ids); + + /* Rotate the chanx_details by an offset of ix - 1, the distance to the most left channel */ + /* For INC_DIRECTION, we use clockwise rotation + * node_id A ----> -----> node_id D + * node_id B ----> / ----> node_id A + * node_id C ----> / ----> node_id B + * node_id D ----> ----> node_id C + */ + chanx_details_tt.rotate_track_node_id(1, INC_DIRECTION, true); + /* For DEC_DIRECTION, we use clockwise rotation + * node_id A <----- <----- node_id B + * node_id B <----- \ <----- node_id C + * node_id C <----- \ <----- node_id D + * node_id D <----- <----- node_id A + */ + chanx_details_tt.rotate_track_node_id(1, DEC_DIRECTION, false); + + track_node_ids = chanx_details_tt.get_track_node_ids(); + chanx_details.set_track_node_ids(track_node_ids); + } + + /* Configure CHANX in this channel */ + load_one_chan_rr_nodes_basic_info(rr_graph, + rr_node_driver_switches, + rr_node_track_ids, + chanx_coord, CHANX, + chanx_details, + segment_infs, + CHANX_COST_INDEX_START); + /* Get a copy of node_ids */ + track_node_ids = chanx_details.get_track_node_ids(); + } + } +} + +/************************************************************************ + * Initialize the basic information of Y-channel rr_nodes: + * coordinates: xlow, ylow, xhigh, yhigh, + * features: capacity, track_ids, ptc_num, direction + ***********************************************************************/ +static +void load_chany_rr_nodes_basic_info(RRGraph& rr_graph, + vtr::vector& rr_node_driver_switches, + std::map>& rr_node_track_ids, + const DeviceGrid& grids, + const size_t& chan_width, + const std::vector& segment_infs) { + + /* For Y-direction Channel: CHANY */ + for (size_t ix = 0; ix < grids.width() - 1; ++ix) { + /* Keep a vector of node_ids for the channels, because we will rotate them when walking through ix */ + std::vector track_node_ids; + + 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); + /* Force node_ids from the previous chanx */ + if (0 < track_node_ids.size()) { + /* Rotate should be done based on a typical case of routing tracks. + * Tracks on the borders are not regularly started and ended, + * which causes the node_rotation malfunction + */ + ChanNodeDetails chany_details_tt = build_unidir_chan_node_details(chan_width, grids.height() - 2, + false, false, segment_infs); + + chany_details_tt.set_track_node_ids(track_node_ids); + /* Rotate the chany_details by an offset of 1*/ + /* For INC_DIRECTION, we use clockwise rotation + * node_id A ----> -----> node_id D + * node_id B ----> / ----> node_id A + * node_id C ----> / ----> node_id B + * node_id D ----> ----> node_id C + */ + chany_details_tt.rotate_track_node_id(1, INC_DIRECTION, true); + /* For DEC_DIRECTION, we use clockwise rotation + * node_id A <----- <----- node_id B + * node_id B <----- \ <----- node_id C + * node_id C <----- \ <----- node_id D + * node_id D <----- <----- node_id A + */ + chany_details_tt.rotate_track_node_id(1, DEC_DIRECTION, false); + + track_node_ids = chany_details_tt.get_track_node_ids(); + chany_details.set_track_node_ids(track_node_ids); + } + /* Configure CHANX in this channel */ + load_one_chan_rr_nodes_basic_info(rr_graph, + rr_node_driver_switches, + rr_node_track_ids, + chany_coord, CHANY, + chany_details, + segment_infs, + CHANX_COST_INDEX_START + segment_infs.size()); + /* Get a copy of node_ids */ + track_node_ids = chany_details.get_track_node_ids(); + } + } +} + +/************************************************************************ + * Reverse the track_ids of CHANX and CHANY nodes in DEC_DIRECTION + * This is required as the track ids are allocated in the sequence + * of incrementing x and y + * However, DEC direction routing tracks should have a reversed sequence in + * track ids + ***********************************************************************/ +static +void reverse_dec_chan_rr_node_track_ids(const RRGraph& rr_graph, + std::map>& rr_node_track_ids) { + for (const RRNodeId& node : rr_graph.nodes()) { + /* Bypass condition: only focus on CHANX and CHANY in DEC_DIRECTION */ + if ( (CHANX != rr_graph.node_type(node)) + && (CHANY != rr_graph.node_type(node)) ) { + continue; + } + /* Reach here, we must have a node of CHANX or CHANY */ + if (DEC_DIRECTION != rr_graph.node_direction(node)) { + continue; + } + std::reverse(rr_node_track_ids[node].begin(), + rr_node_track_ids[node].end() ); + } +} + /************************************************************************ * 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, + std::map>& rr_node_track_ids, const DeviceGrid& grids, + const vtr::Point& chan_width, + const std::vector& segment_infs, const RRSwitchId& wire_to_ipin_switch, const RRSwitchId& delayless_switch) { load_grid_nodes_basic_info(rr_graph, @@ -752,6 +962,23 @@ void create_tileable_rr_graph_nodes(RRGraph& rr_graph, wire_to_ipin_switch, delayless_switch); + load_chanx_rr_nodes_basic_info(rr_graph, + rr_node_driver_switches, + rr_node_track_ids, + grids, + chan_width.x(), + segment_infs); + + load_chany_rr_nodes_basic_info(rr_graph, + rr_node_driver_switches, + rr_node_track_ids, + grids, + chan_width.y(), + segment_infs); + + reverse_dec_chan_rr_node_track_ids(rr_graph, + rr_node_track_ids); + } } /* 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 7cd8c673a..a69cd187c 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 @@ -29,10 +29,14 @@ void alloc_tileable_rr_graph_nodes(RRGraph& rr_graph, void create_tileable_rr_graph_nodes(RRGraph& rr_graph, vtr::vector& rr_node_driver_switches, + std::map>& rr_node_track_ids, const DeviceGrid& grids, + const vtr::Point& chan_width, + const std::vector& segment_infs, const RRSwitchId& wire_to_ipin_switch, const RRSwitchId& delayless_switch); + } /* end namespace openfpga */ #endif From 8d350ee22ff41af0877a9781715b3d44bacf58c5 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 5 Mar 2020 20:50:21 -0700 Subject: [PATCH 2/2] adapt tileable rr_graph edge builder to rr_graph object --- .../tileable_rr_graph_edge_builder.cpp | 169 ++++++++++++++++++ .../tileable_rr_graph_edge_builder.h | 42 +++++ .../tileable_rr_graph_gsb.cpp | 8 +- .../tileable_rr_graph/tileable_rr_graph_gsb.h | 4 +- 4 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 vpr/src/tileable_rr_graph/tileable_rr_graph_edge_builder.cpp create mode 100644 vpr/src/tileable_rr_graph/tileable_rr_graph_edge_builder.h diff --git a/vpr/src/tileable_rr_graph/tileable_rr_graph_edge_builder.cpp b/vpr/src/tileable_rr_graph/tileable_rr_graph_edge_builder.cpp new file mode 100644 index 000000000..185e4923b --- /dev/null +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_edge_builder.cpp @@ -0,0 +1,169 @@ +/************************************************************************ + * This file contains functions that are used to build edges + * between nodes of a tileable routing resource graph + ***********************************************************************/ +#include + +/* Headers from vtrutil library */ +#include "vtr_assert.h" +#include "vtr_log.h" +#include "vtr_time.h" + +#include "vpr_utils.h" + +#include "rr_graph_builder_utils.h" +#include "tileable_rr_graph_gsb.h" +#include "tileable_rr_graph_edge_builder.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/************************************************************************ + * Build the edges for all the SOURCE and SINKs nodes: + * 1. create edges between SOURCE and OPINs + ***********************************************************************/ +static +void build_rr_graph_edges_for_source_nodes(RRGraph& rr_graph, + const vtr::vector& rr_node_driver_switches, + const DeviceGrid& grids) { + for (const RRNodeId& node : rr_graph.nodes()) { + /* Bypass all the non OPIN nodes */ + if (OPIN != rr_graph.node_type(node)) { + continue; + } + /* Now, we have an OPIN node, we get the source node index */ + short xlow = rr_graph.node_xlow(node); + short ylow = rr_graph.node_ylow(node); + short src_node_class_num = get_grid_pin_class_index(grids[xlow][ylow], + rr_graph.node_pin_num(node)); + + /* Create edges between SOURCE and OPINs */ + const RRNodeId& src_node = rr_graph.find_node(xlow - grids[xlow][ylow].width_offset, + ylow - grids[xlow][ylow].height_offset, + SOURCE, src_node_class_num); + VTR_ASSERT(true == rr_graph.valid_node_id(src_node)); + + /* add edges to the src_node */ + rr_graph.create_edge(src_node, node, rr_node_driver_switches[node]); + } +} + +/************************************************************************ + * Build the edges for all the SINKs nodes: + * 1. create edges between IPINs and SINKs + ***********************************************************************/ +static +void build_rr_graph_edges_for_sink_nodes(RRGraph& rr_graph, + const vtr::vector& rr_node_driver_switches, + const DeviceGrid& grids) { + for (const RRNodeId& node : rr_graph.nodes()) { + /* Bypass all the non IPIN nodes */ + if (IPIN != rr_graph.node_type(node)) { + continue; + } + /* Now, we have an OPIN node, we get the source node index */ + short xlow = rr_graph.node_xlow(node); + short ylow = rr_graph.node_ylow(node); + short sink_node_class_num = get_grid_pin_class_index(grids[xlow][ylow], + rr_graph.node_pin_num(node)); + /* 1. create edges between IPINs and SINKs */ + const RRNodeId& sink_node = rr_graph.find_node(xlow - grids[xlow][ylow].width_offset, + ylow - grids[xlow][ylow].height_offset, + SINK, sink_node_class_num); + VTR_ASSERT(true == rr_graph.valid_node_id(sink_node)); + + /* add edges to connect the IPIN node to SINK nodes */ + rr_graph.create_edge(node, sink_node, rr_node_driver_switches[sink_node]); + } +} + +/************************************************************************ + * Build the edges of each rr_node tile by tile: + * We classify rr_nodes into a general switch block (GSB) data structure + * where we create edges to each rr_nodes in the GSB with respect to + * Fc_in and Fc_out, switch block patterns + * For each GSB: + * 1. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) + * 2. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) + * 3. create edges between OPINs and IPINs (direct-connections) + ***********************************************************************/ +void build_rr_graph_edges(RRGraph& rr_graph, + const vtr::vector& rr_node_driver_switches, + const DeviceGrid& grids, + const vtr::Point& device_chan_width, + const std::vector& segment_inf, + int** Fc_in, int** Fc_out, + const e_switch_block_type& sb_type, const int& Fs, + const e_switch_block_type& sb_subtype, const int& subFs, + const bool& wire_opposite_side) { + + /* Create edges for SOURCE and SINK nodes for a tileable rr_graph */ + build_rr_graph_edges_for_source_nodes(rr_graph, rr_node_driver_switches, grids); + build_rr_graph_edges_for_sink_nodes(rr_graph, rr_node_driver_switches, grids); + + vtr::Point gsb_range(grids.width() - 2, grids.height() - 2); + + /* Go Switch Block by Switch Block */ + for (size_t ix = 0; ix <= gsb_range.x(); ++ix) { + for (size_t iy = 0; iy <= gsb_range.y(); ++iy) { + //vpr_printf(TIO_MESSAGE_INFO, "Building edges for GSB[%lu][%lu]\n", ix, iy); + + vtr::Point gsb_coord(ix, iy); + /* Create a GSB object */ + const RRGSB& rr_gsb = build_one_tileable_rr_gsb(grids, rr_graph, + device_chan_width, segment_inf, + gsb_coord); + + /* adapt the track_to_ipin_lookup for the GSB nodes */ + t_track2pin_map track2ipin_map; /* [0..track_gsb_side][0..num_tracks][ipin_indices] */ + track2ipin_map = build_gsb_track_to_ipin_map(rr_graph, rr_gsb, grids, segment_inf, Fc_in); + + /* adapt the opin_to_track_map for the GSB nodes */ + t_pin2track_map opin2track_map; /* [0..gsb_side][0..num_opin_node][track_indices] */ + opin2track_map = build_gsb_opin_to_track_map(rr_graph, rr_gsb, grids, segment_inf, Fc_out); + + /* adapt the switch_block_conn for the GSB nodes */ + t_track2track_map sb_conn; /* [0..from_gsb_side][0..chan_width-1][track_indices] */ + sb_conn = build_gsb_track_to_track_map(rr_graph, rr_gsb, + sb_type, Fs, sb_subtype, subFs, wire_opposite_side, + segment_inf); + + /* Build edges for a GSB */ + build_edges_for_one_tileable_rr_gsb(rr_graph, rr_gsb, + track2ipin_map, opin2track_map, + sb_conn, rr_node_driver_switches); + /* Finish this GSB, go to the next*/ + } + } +} + +/************************************************************************ + * Build direct edges for Grids * + ***********************************************************************/ +void build_rr_graph_direct_connections(RRGraph& rr_graph, + const DeviceGrid& grids, + const RRSwitchId& delayless_switch, + const std::vector& directs, + const std::vector& clb_to_clb_directs) { + 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; + } + vtr::Point from_grid_coordinate(ix, iy); + build_direct_connections_for_one_gsb(rr_graph, + grids, + from_grid_coordinate, + delayless_switch, + directs, clb_to_clb_directs); + } + } +} + +} /* end namespace openfpga */ diff --git a/vpr/src/tileable_rr_graph/tileable_rr_graph_edge_builder.h b/vpr/src/tileable_rr_graph/tileable_rr_graph_edge_builder.h new file mode 100644 index 000000000..34c2ced24 --- /dev/null +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_edge_builder.h @@ -0,0 +1,42 @@ +#ifndef TILEABLE_RR_GRAPH_EDGE_BUILDER_H +#define TILEABLE_RR_GRAPH_EDGE_BUILDER_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include + +/* Headers from vtrutil library */ +#include "vtr_geometry.h" + +#include "physical_types.h" +#include "device_grid.h" +#include "rr_graph_obj.h" +#include "clb2clb_directs.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +void build_rr_graph_edges(RRGraph& rr_graph, + const vtr::vector& rr_node_driver_switches, + const DeviceGrid& grids, + const vtr::Point& device_chan_width, + const std::vector& segment_inf, + int** Fc_in, int** Fc_out, + const e_switch_block_type& sb_type, const int& Fs, + const e_switch_block_type& sb_subtype, const int& subFs, + const bool& wire_opposite_side); + +void build_rr_graph_direct_connections(RRGraph& rr_graph, + const DeviceGrid& grids, + const RRSwitchId& delayless_switch, + const std::vector& directs, + const std::vector& clb_to_clb_directs); + +} /* end namespace openfpga */ + +#endif 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 9cbc69dff..e2bf6e4ce 100755 --- a/vpr/src/tileable_rr_graph/tileable_rr_graph_gsb.cpp +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_gsb.cpp @@ -620,7 +620,7 @@ RRChan build_one_tileable_rr_chan(const vtr::Point& chan_coordinate, ***********************************************************************/ RRGSB build_one_tileable_rr_gsb(const DeviceGrid& grids, const RRGraph& rr_graph, - const std::vector& device_chan_width, + const vtr::Point& device_chan_width, const std::vector& segment_inf, const vtr::Point& gsb_coordinate) { /* Create an object to return */ @@ -650,9 +650,9 @@ RRGSB build_one_tileable_rr_gsb(const DeviceGrid& grids, /* Build a segment details, where we need the segment ids for building rr_chan * 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, + ChanNodeDetails chanx_details = build_unidir_chan_node_details(device_chan_width.x(), grids.width() - 1, false, false, segment_inf); - ChanNodeDetails chany_details = build_unidir_chan_node_details(device_chan_width[1], grids.height() - 1, + ChanNodeDetails chany_details = build_unidir_chan_node_details(device_chan_width.y(), grids.height() - 1, false, false, segment_inf); switch (side) { @@ -907,7 +907,7 @@ void build_edges_for_one_tileable_rr_gsb(RRGraph& rr_graph, const t_track2pin_map& track2ipin_map, const t_pin2track_map& opin2track_map, const t_track2track_map& track2track_map, - const vtr::vector rr_node_driver_switches) { + const vtr::vector& rr_node_driver_switches) { /* Walk through each sides */ for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { diff --git a/vpr/src/tileable_rr_graph/tileable_rr_graph_gsb.h b/vpr/src/tileable_rr_graph/tileable_rr_graph_gsb.h index 170249f74..7c7568fb9 100755 --- a/vpr/src/tileable_rr_graph/tileable_rr_graph_gsb.h +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_gsb.h @@ -44,7 +44,7 @@ t_track2track_map build_gsb_track_to_track_map(const RRGraph& rr_graph, RRGSB build_one_tileable_rr_gsb(const DeviceGrid& grids, const RRGraph& rr_graph, - const std::vector& device_chan_width, + const vtr::Point& device_chan_width, const std::vector& segment_inf, const vtr::Point& gsb_coordinate); @@ -53,7 +53,7 @@ void build_edges_for_one_tileable_rr_gsb(RRGraph& rr_graph, const t_track2pin_map& track2ipin_map, const t_pin2track_map& opin2track_map, const t_track2track_map& track2track_map, - const vtr::vector rr_node_driver_switches); + const vtr::vector& rr_node_driver_switches); t_track2pin_map build_gsb_track_to_ipin_map(const RRGraph& rr_graph, const RRGSB& rr_gsb,