From baab9c4a21e856d8202aca4c57a561fbb112f4aa Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 20 Jun 2019 18:17:07 -0600 Subject: [PATCH] basically finished the coding of tileable rr_graph generator. testing to go --- .../rr_graph/rr_graph_tileable_builder.c | 818 +--------- .../rr_graph/rr_graph_tileable_builder.h | 32 +- .../device/rr_graph/rr_graph_tileable_gsb.cpp | 1346 +++++++++++++++++ .../device/rr_graph/rr_graph_tileable_gsb.h | 62 + .../rr_graph/rr_graph_tileable_sbox.cpp | 461 ------ .../device/rr_graph/rr_graph_tileable_sbox.h | 20 - vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp | 59 + vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h | 5 + vpr7_x2p/vpr/SRC/route/check_rr_graph.c | 15 +- vpr7_x2p/vpr/SRC/route/check_rr_graph.h | 30 +- vpr7_x2p/vpr/SRC/route/rr_graph.c | 10 +- vpr7_x2p/vpr/SRC/route/rr_graph.h | 6 +- .../vpr/SRC/route/rr_graph_indexed_data.c | 6 +- .../vpr/SRC/route/rr_graph_indexed_data.h | 2 +- vpr7_x2p/vpr/SRC/util/vpr_utils.c | 4 +- vpr7_x2p/vpr/SRC/util/vpr_utils.h | 2 +- 16 files changed, 1596 insertions(+), 1282 deletions(-) create mode 100755 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp create mode 100755 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h delete mode 100755 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp delete mode 100755 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 58010142e..e8d4a0365 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -56,26 +56,24 @@ #include "ReadOptions.h" #include "rr_graph.h" #include "rr_graph2.h" +#include "check_rr_graph.h" #include "route_common.h" #include "fpga_x2p_types.h" #include "rr_graph_tileable_builder.h" -#include "fpga_x2p_backannotate_utils.h" -#include "my_free_fwd.h" #include "rr_blocks.h" #include "chan_node_details.h" #include "device_coordinator.h" -#include "rr_graph_tileable_sbox.h" +#include "rr_graph_tileable_gsb.h" /************************************************************************ * Local data stuctures in the file ***********************************************************************/ -typedef std::vector>> t_track2pin_map; -typedef std::vector>> t_pin2track_map; /************************************************************************ * Local function in the file ***********************************************************************/ + /************************************************************************ * Initialize a rr_node ************************************************************************/ @@ -153,9 +151,9 @@ void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node) { * In this way, we can assign the number of tracks with repect to frequency ***********************************************************************/ static -std::vector get_num_tracks_per_seg_type(size_t chan_width, - std::vector segment_inf, - bool use_full_seg_groups) { +std::vector get_num_tracks_per_seg_type(const size_t chan_width, + const std::vector segment_inf, + const bool use_full_seg_groups) { std::vector result; std::vector demand; /* Make sure a clean start */ @@ -269,26 +267,26 @@ std::vector get_num_tracks_per_seg_type(size_t chan_width, * in X-direction and Y-direction channels!!! * So we will load segment details for different channels ***********************************************************************/ -static -ChanNodeDetails build_unidir_chan_node_details(size_t chan_width, size_t max_seg_length, - enum e_side device_side, - std::vector segment_inf) { +ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const size_t max_seg_length, + const enum e_side device_side, + const std::vector segment_inf) { ChanNodeDetails chan_node_details; + size_t actual_chan_width = chan_width; /* Correct the chan_width: it should be an even number */ - if (0 != chan_width % 2) { - chan_width++; /* increment it to be even */ + if (0 != actual_chan_width % 2) { + actual_chan_width++; /* increment it to be even */ } - assert (0 == chan_width % 2); + assert (0 == actual_chan_width % 2); /* Reserve channel width */ chan_node_details.reserve(chan_width); /* Return if zero width is forced */ - if (0 == chan_width) { + if (0 == actual_chan_width) { return chan_node_details; } /* Find the number of segments required by each group */ - std::vector num_tracks = get_num_tracks_per_seg_type(chan_width/2, segment_inf, TRUE); + std::vector num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, TRUE); /* Add node to ChanNodeDetails */ size_t cur_track = 0; @@ -319,7 +317,7 @@ ChanNodeDetails build_unidir_chan_node_details(size_t chan_width, size_t max_seg } } /* Check if all the tracks have been satisified */ - assert (cur_track == chan_width); + assert (cur_track == actual_chan_width); /* If this is on the border of a device, segments should start */ switch (device_side) { @@ -375,7 +373,10 @@ enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size, * For others, we consider all the sides ***********************************************************************/ static -std::vector get_grid_side_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, enum e_side pin_side, int pin_height) { +std::vector get_grid_side_pins(const t_grid_tile& cur_grid, + const enum e_pin_type pin_type, + const enum e_side pin_side, + const int pin_height) { std::vector pin_list; /* Make sure a clear start */ pin_list.clear(); @@ -395,7 +396,7 @@ std::vector get_grid_side_pins(const t_grid_tile& cur_grid, enum e_pin_type * For others, we consider all the sides ***********************************************************************/ static -size_t get_grid_num_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, enum e_side io_side) { +size_t get_grid_num_pins(const t_grid_tile& cur_grid, const enum e_pin_type pin_type, const enum e_side io_side) { size_t num_pins = 0; Side io_side_manager(io_side); /* For IO_TYPE sides */ @@ -422,9 +423,9 @@ size_t get_grid_num_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, ***********************************************************************/ static std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& device_size, - std::vector> grids, - std::vector chan_width, - std::vector segment_infs) { + const std::vector> grids, + const std::vector chan_width, + const std::vector segment_infs) { std::vector num_rr_nodes_per_type; /* reserve the vector: * we have the follow type: @@ -525,8 +526,10 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi * Configure one rr_node to the fast-look up of a rr_graph ***********************************************************************/ static -void load_one_node_to_rr_graph_fast_lookup(t_rr_graph* rr_graph, int node_index, - t_rr_type node_type, int x, int y, int ptc_num) { +void load_one_node_to_rr_graph_fast_lookup(t_rr_graph* rr_graph, const int node_index, + const t_rr_type node_type, + const int x, const int y, + const int ptc_num) { /* check the size of ivec (nelem), * if the ptc_num exceeds the size limit, we realloc the ivec */ if (ptc_num > rr_graph->rr_node_indices[node_type][x][y].nelem - 1) { @@ -545,10 +548,10 @@ void load_one_node_to_rr_graph_fast_lookup(t_rr_graph* rr_graph, int node_index, static void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator, const t_grid_tile& cur_grid, - enum e_side io_side, + const enum e_side io_side, t_rr_graph* rr_graph, size_t* cur_node_id, - int wire_to_ipin_switch, int delayless_switch) { + const int wire_to_ipin_switch, const int delayless_switch) { Side io_side_manager(io_side); /* Walk through the height of each grid, * get pins and configure the rr_nodes */ @@ -791,10 +794,10 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator static void load_rr_nodes_basic_info(t_rr_graph* rr_graph, const DeviceCoordinator& device_size, - std::vector> grids, - std::vector chan_width, - std::vector segment_infs, - int wire_to_ipin_switch, int delayless_switch) { + const std::vector> grids, + const std::vector chan_width, + const std::vector segment_infs, + const int wire_to_ipin_switch, const int delayless_switch) { /* counter */ size_t cur_node_id = 0; /* configure by node type */ @@ -966,665 +969,6 @@ void alloc_rr_graph_fast_lookup(const DeviceCoordinator& device_size, return; } -/* Build a RRChan Object with the given channel type and coorindators */ -static -RRChan build_one_tileable_rr_chan(const DeviceCoordinator& chan_coordinator, - t_rr_type chan_type, - const t_rr_graph* rr_graph, - const ChanNodeDetails& chan_details) { - int chan_width = 0; - t_rr_node** chan_rr_nodes = NULL; - - /* Create a rr_chan object and check if it is unique in the graph */ - RRChan rr_chan; - /* Fill the information */ - rr_chan.set_type(chan_type); - - /* Collect rr_nodes for this channel */ - chan_rr_nodes = get_chan_rr_nodes(&chan_width, chan_type, chan_coordinator.get_x(), chan_coordinator.get_y(), - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - - /* Reserve */ - /* rr_chan.reserve_node(size_t(chan_width)); */ - - /* Fill the rr_chan */ - for (size_t itrack = 0; itrack < size_t(chan_width); ++itrack) { - size_t iseg = chan_details.get_track_segment_id(itrack); - rr_chan.add_node(chan_rr_nodes[itrack], iseg); - } - - /* Free rr_nodes */ - my_free(chan_rr_nodes); - - return rr_chan; -} - -/*********************************************************************** - * Build a General Switch Block (GSB) - * which includes: - * [I] A Switch Box subckt consists of following ports: - * 1. Channel Y [x][y] inputs - * 2. Channel X [x+1][y] inputs - * 3. Channel Y [x][y-1] outputs - * 4. Channel X [x][y] outputs - * 5. Grid[x][y+1] Right side outputs pins - * 6. Grid[x+1][y+1] Left side output pins - * 7. Grid[x+1][y+1] Bottom side output pins - * 8. Grid[x+1][y] Top side output pins - * 9. Grid[x+1][y] Left side output pins - * 10. Grid[x][y] Right side output pins - * 11. Grid[x][y] Top side output pins - * 12. Grid[x][y+1] Bottom side output pins - * - * -------------- -------------- - * | | CBY | | - * | Grid | ChanY | Grid | - * | [x][y+1] | [x][y+1] | [x+1][y+1] | - * | | | | - * -------------- -------------- - * ---------- - * ChanX & CBX | Switch | ChanX - * [x][y] | Box | [x+1][y] - * | [x][y] | - * ---------- - * -------------- -------------- - * | | | | - * | Grid | ChanY | Grid | - * | [x][y] | [x][y] | [x+1][y] | - * | | | | - * -------------- -------------- - * For channels chanY with INC_DIRECTION on the top side, they should be marked as outputs - * For channels chanY with DEC_DIRECTION on the top side, they should be marked as inputs - * For channels chanY with INC_DIRECTION on the bottom side, they should be marked as inputs - * For channels chanY with DEC_DIRECTION on the bottom side, they should be marked as outputs - * For channels chanX with INC_DIRECTION on the left side, they should be marked as inputs - * For channels chanX with DEC_DIRECTION on the left side, they should be marked as outputs - * For channels chanX with INC_DIRECTION on the right side, they should be marked as outputs - * For channels chanX with DEC_DIRECTION on the right side, they should be marked as inputs - * - * [II] A X-direction Connection Block [x][y] - * The connection block shares the same routing channel[x][y] with the Switch Block - * We just need to fill the ipin nodes at TOP and BOTTOM sides - * as well as properly fill the ipin_grid_side information - * [III] A Y-direction Connection Block [x][y+1] - * The connection block shares the same routing channel[x][y+1] with the Switch Block - * We just need to fill the ipin nodes at LEFT and RIGHT sides - * as well as properly fill the ipin_grid_side information - ***********************************************************************/ -static -RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, - std::vector device_chan_width, - std::vector segment_inf, - const DeviceCoordinator& gsb_coordinator, - t_rr_graph* rr_graph) { - /* Create an object to return */ - RRGSB rr_gsb; - - /* Check */ - assert(gsb_coordinator.get_x() <= device_range.get_x()); - assert(gsb_coordinator.get_y() <= device_range.get_y()); - - /* Coordinator initialization */ - rr_gsb.set_coordinator(gsb_coordinator.get_x(), gsb_coordinator.get_y()); - - /* Basic information*/ - rr_gsb.init_num_sides(4); /* Fixed number of sides */ - - /* Find all rr_nodes of channels */ - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - /* Local variables inside this for loop */ - Side side_manager(side); - DeviceCoordinator coordinator = rr_gsb.get_side_block_coordinator(side_manager.get_side()); - RRChan rr_chan; - int temp_num_opin_rr_nodes[2] = {0,0}; - t_rr_node** temp_opin_rr_node[2] = {NULL, NULL}; - enum e_side opin_grid_side[2] = {NUM_SIDES, NUM_SIDES}; - enum PORTS chan_dir_to_port_dir_mapping[2] = {OUT_PORT, IN_PORT}; /* 0: INC_DIRECTION => ?; 1: DEC_DIRECTION => ? */ - /* 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], device_range.get_x() - 1, - NUM_SIDES, segment_inf); - ChanNodeDetails chany_details = build_unidir_chan_node_details(device_chan_width[1], device_range.get_y() - 1, - NUM_SIDES, segment_inf); - - switch (side) { - case TOP: /* TOP = 0 */ - /* For the bording, we should take special care */ - if (gsb_coordinator.get_y() == device_range.get_y()) { - rr_gsb.clear_one_side(side_manager.get_side()); - break; - } - /* Routing channels*/ - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - /* Create a rr_chan object and check if it is unique in the graph */ - rr_chan = build_one_tileable_rr_chan(coordinator, CHANY, rr_graph, chany_details); - chan_dir_to_port_dir_mapping[0] = OUT_PORT; /* INC_DIRECTION => OUT_PORT */ - chan_dir_to_port_dir_mapping[1] = IN_PORT; /* DEC_DIRECTION => IN_PORT */ - - /* Build the Switch block: opin and opin_grid_side */ - /* Include Grid[x][y+1] RIGHT side outputs pins */ - temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], - OPIN, gsb_coordinator.get_x(), gsb_coordinator.get_y() + 1, 1, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - /* Include Grid[x+1][y+1] Left side output pins */ - temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], - OPIN, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y() + 1, 3, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - - /* Assign grid side of OPIN */ - /* Grid[x][y+1] RIGHT side outputs pins */ - opin_grid_side[0] = RIGHT; - /* Grid[x+1][y+1] left side outputs pins */ - opin_grid_side[1] = LEFT; - break; - case RIGHT: /* RIGHT = 1 */ - /* For the bording, we should take special care */ - if (gsb_coordinator.get_x() == device_range.get_x()) { - rr_gsb.clear_one_side(side_manager.get_side()); - break; - } - /* Routing channels*/ - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - /* Collect rr_nodes for Tracks for top: chany[x][y+1] */ - /* Create a rr_chan object and check if it is unique in the graph */ - rr_chan = build_one_tileable_rr_chan(coordinator, CHANX, rr_graph, chanx_details); - chan_dir_to_port_dir_mapping[0] = OUT_PORT; /* INC_DIRECTION => OUT_PORT */ - chan_dir_to_port_dir_mapping[1] = IN_PORT; /* DEC_DIRECTION => IN_PORT */ - - /* Build the Switch block: opin and opin_grid_side */ - /* include Grid[x+1][y+1] Bottom side output pins */ - temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], - OPIN, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y() + 1, 2, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - /* include Grid[x+1][y] Top side output pins */ - temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], - OPIN, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y(), 0, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - /* Assign grid side of OPIN */ - /* Grid[x+1][y+1] BOTTOM side outputs pins */ - opin_grid_side[0] = BOTTOM; - /* Grid[x+1][y] TOP side outputs pins */ - opin_grid_side[1] = TOP; - break; - case BOTTOM: /* BOTTOM = 2*/ - /* For the bording, we should take special care */ - if (gsb_coordinator.get_y() == 0) { - rr_gsb.clear_one_side(side_manager.get_side()); - break; - } - /* Routing channels*/ - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - /* Collect rr_nodes for Tracks for bottom: chany[x][y] */ - /* Create a rr_chan object and check if it is unique in the graph */ - rr_chan = build_one_tileable_rr_chan(coordinator, CHANY, rr_graph, chany_details); - chan_dir_to_port_dir_mapping[0] = IN_PORT; /* INC_DIRECTION => IN_PORT */ - chan_dir_to_port_dir_mapping[1] = OUT_PORT; /* DEC_DIRECTION => OUT_PORT */ - - /* Build the Switch block: opin and opin_grid_side */ - /* include Grid[x+1][y] Left side output pins */ - temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], - OPIN, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y(), 3, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - /* include Grid[x][y] Right side output pins */ - temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], - OPIN, gsb_coordinator.get_x(), gsb_coordinator.get_y(), 1, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - /* Assign grid side of OPIN */ - /* Grid[x+1][y] LEFT side outputs pins */ - opin_grid_side[0] = LEFT; - /* Grid[x][y] RIGHT side outputs pins */ - opin_grid_side[1] = RIGHT; - break; - case LEFT: /* LEFT = 3 */ - /* For the bording, we should take special care */ - if (gsb_coordinator.get_x() == 0) { - rr_gsb.clear_one_side(side_manager.get_side()); - break; - } - /* Routing channels*/ - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - /* Collect rr_nodes for Tracks for left: chanx[x][y] */ - /* Create a rr_chan object and check if it is unique in the graph */ - rr_chan = build_one_tileable_rr_chan(coordinator, CHANX, rr_graph, chanx_details); - chan_dir_to_port_dir_mapping[0] = IN_PORT; /* INC_DIRECTION => IN_PORT */ - chan_dir_to_port_dir_mapping[1] = OUT_PORT; /* DEC_DIRECTION => OUT_PORT */ - - /* Build the Switch block: opin and opin_grid_side */ - /* include Grid[x][y+1] Bottom side outputs pins */ - temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], - OPIN, gsb_coordinator.get_x(), gsb_coordinator.get_y() + 1, 2, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - /* include Grid[x][y] Top side output pins */ - temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], - OPIN, gsb_coordinator.get_x(), gsb_coordinator.get_y(), 0, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - - /* Grid[x][y+1] BOTTOM side outputs pins */ - opin_grid_side[0] = BOTTOM; - /* Grid[x][y] TOP side outputs pins */ - opin_grid_side[1] = TOP; - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d])Invalid side index!\n", - __FILE__, __LINE__); - exit(1); - } - - /* Organize a vector of port direction */ - if (0 < rr_chan.get_chan_width()) { - std::vector rr_chan_dir; - rr_chan_dir.resize(rr_chan.get_chan_width()); - for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) { - /* Identify the directionality, record it in rr_node_direction */ - if (INC_DIRECTION == rr_chan.get_node(itrack)->direction) { - rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[0]; - } else { - assert (DEC_DIRECTION == rr_chan.get_node(itrack)->direction); - rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[1]; - } - } - /* Fill chan_rr_nodes */ - rr_gsb.add_chan_node(side_manager.get_side(), rr_chan, rr_chan_dir); - } - - /* Fill opin_rr_nodes */ - /* Copy from temp_opin_rr_node to opin_rr_node */ - for (int inode = 0; inode < temp_num_opin_rr_nodes[0]; ++inode) { - /* Grid[x+1][y+1] Bottom side outputs pins */ - rr_gsb.add_opin_node(temp_opin_rr_node[0][inode], side_manager.get_side(), opin_grid_side[0]); - } - for (int inode = 0; inode < temp_num_opin_rr_nodes[1]; ++inode) { - /* Grid[x+1][y] TOP side outputs pins */ - rr_gsb.add_opin_node(temp_opin_rr_node[1][inode], side_manager.get_side(), opin_grid_side[1]); - } - - /* Clean ipin_rr_nodes */ - /* We do not have any IPIN for a Switch Block */ - rr_gsb.clear_ipin_nodes(side_manager.get_side()); - - /* Free */ - temp_num_opin_rr_nodes[0] = 0; - my_free(temp_opin_rr_node[0]); - temp_num_opin_rr_nodes[1] = 0; - my_free(temp_opin_rr_node[1]); - /* Set them to NULL, avoid double free errors */ - temp_opin_rr_node[0] = NULL; - temp_opin_rr_node[1] = NULL; - opin_grid_side[0] = NUM_SIDES; - opin_grid_side[1] = NUM_SIDES; - } - - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - /* Local variables inside this for loop */ - Side side_manager(side); - size_t ix; - size_t iy; - enum e_side chan_side; - int num_temp_ipin_rr_nodes = 0; - t_rr_node** temp_ipin_rr_node = NULL; - enum e_side ipin_rr_node_grid_side; - - switch (side) { - case TOP: /* TOP = 0 */ - /* For the bording, we should take special care */ - /* Check if left side chan width is 0 or not */ - chan_side = LEFT; - /* Build the connection block: ipin and ipin_grid_side */ - /* BOTTOM side INPUT Pins of Grid[x][y+1] */ - ix = rr_gsb.get_sb_x(); - iy = rr_gsb.get_sb_y() + 1; - ipin_rr_node_grid_side = BOTTOM; - break; - case RIGHT: /* RIGHT = 1 */ - /* For the bording, we should take special care */ - /* Check if TOP side chan width is 0 or not */ - chan_side = TOP; - /* Build the connection block: ipin and ipin_grid_side */ - /* LEFT side INPUT Pins of Grid[x+1][y+1] */ - ix = rr_gsb.get_sb_x() + 1; - iy = rr_gsb.get_sb_y() + 1; - ipin_rr_node_grid_side = LEFT; - break; - case BOTTOM: /* BOTTOM = 2*/ - /* For the bording, we should take special care */ - /* Check if left side chan width is 0 or not */ - chan_side = LEFT; - /* Build the connection block: ipin and ipin_grid_side */ - /* TOP side INPUT Pins of Grid[x][y] */ - ix = rr_gsb.get_sb_x(); - iy = rr_gsb.get_sb_y(); - ipin_rr_node_grid_side = TOP; - break; - case LEFT: /* LEFT = 3 */ - /* For the bording, we should take special care */ - /* Check if left side chan width is 0 or not */ - chan_side = TOP; - /* Build the connection block: ipin and ipin_grid_side */ - /* RIGHT side INPUT Pins of Grid[x][y+1] */ - ix = rr_gsb.get_sb_x(); - iy = rr_gsb.get_sb_y() + 1; - ipin_rr_node_grid_side = RIGHT; - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d])Invalid side index!\n", - __FILE__, __LINE__); - exit(1); - } - - /* If there is no channel at this side, we skip ipin_node annotation */ - if (0 == rr_gsb.get_chan_width(chan_side)) { - continue; - } - /* Collect IPIN rr_nodes*/ - temp_ipin_rr_node = get_grid_side_pin_rr_nodes(&(num_temp_ipin_rr_nodes), - IPIN, ix, iy, ipin_rr_node_grid_side, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - /* Fill the ipin nodes of RRGSB */ - for (int inode = 0; inode < num_temp_ipin_rr_nodes; ++inode) { - rr_gsb.add_ipin_node(temp_ipin_rr_node[inode], side_manager.get_side(), ipin_rr_node_grid_side); - } - /* Free */ - num_temp_ipin_rr_nodes = 0; - my_free(temp_ipin_rr_node); - } - - return rr_gsb; - -} - -/************************************************************************ - * Add a edge connecting two rr_nodes - * For src rr_node, update the edge list and update switch_id, - * For des rr_node, update the fan_in - ***********************************************************************/ -static -void add_one_edge_for_two_rr_nodes(t_rr_graph* rr_graph, - int src_rr_node_id, - int des_rr_node_id, - short switch_id) { - /* Check */ - assert ( (-1 < src_rr_node_id) && (src_rr_node_id < rr_graph->num_rr_nodes) ); - assert ( (-1 < des_rr_node_id) && (des_rr_node_id < rr_graph->num_rr_nodes) ); - - t_rr_node* src_rr_node = &(rr_graph->rr_node[src_rr_node_id]); - t_rr_node* des_rr_node = &(rr_graph->rr_node[des_rr_node_id]); - - /* Allocate edge and switch to src_rr_node */ - src_rr_node->num_edges++; - if (NULL == src_rr_node->edges) { - /* calloc */ - src_rr_node->edges = (int*) my_calloc( src_rr_node->num_edges, sizeof(int) ); - src_rr_node->switches = (short*) my_calloc( src_rr_node->num_edges, sizeof(short) ); - } else { - /* realloc */ - src_rr_node->edges = (int*) my_realloc(src_rr_node->edges, - src_rr_node->num_edges * sizeof(int)); - src_rr_node->switches = (short*) my_realloc(src_rr_node->switches, - src_rr_node->num_edges * sizeof(short)); - } - /* Fill edge and switch info */ - src_rr_node->edges[src_rr_node->num_edges - 1] = des_rr_node_id; - src_rr_node->switches[src_rr_node->num_edges - 1] = switch_id; - - /* Update the des_rr_node */ - des_rr_node->fan_in++; - - return; -} - -/************************************************************************ - * Create edges for each rr_node of a General Switch Blocks (GSB): - * 1. create edges between SOURCE and OPINs - * 2. create edges between IPINs and SINKs - * 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) - * 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) - * 5. create edges between OPINs and IPINs (direct-connections) - ***********************************************************************/ -static -void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, - t_track2pin_map track2ipin_map, - t_pin2track_map opin2track_map, - t_track2track_map track2track_map) { - /* Check rr_gsb */ - assert (NULL != rr_gsb); - - /* Walk through each sides */ - for (size_t side = 0; side < rr_gsb->get_num_sides(); ++side) { - Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); - - /* Find OPINs */ - for (size_t inode = 0; inode < rr_gsb->get_num_opin_nodes(gsb_side); ++inode) { - t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode); - /* 1. create edges between SOURCE and OPINs */ - int src_node_id = get_rr_node_index(opin_node->xlow, opin_node->ylow, - SOURCE, opin_node->ptc_num, - rr_graph->rr_node_indices); - /* add edges to the src_node */ - add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, opin_node - rr_graph->rr_node, - opin_node->driver_switch); - /* 2. create edges between OPINs and CHANX|CHANY, using opin2track_map */ - int num_edges = opin2track_map[side_manager.to_size_t()][inode].size(); - for (int iedge = 0; iedge < num_edges; ++iedge) { - int track_node_id = opin2track_map[side_manager.to_size_t()][inode][iedge]; - /* add edges to the chan_node */ - add_one_edge_for_two_rr_nodes(rr_graph, opin_node - rr_graph->rr_node, track_node_id, - rr_graph->rr_node[track_node_id].driver_switch); - } - } - - /* Find IPINs */ - for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) { - t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode); - /* 3. create edges between IPINs and SINKs */ - int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow, - SINK, ipin_node->ptc_num, - rr_graph->rr_node_indices); - /* add edges to connect the IPIN node to SINK nodes */ - add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id, - rr_graph->rr_node[sink_node_id].driver_switch); - } - /* Find CHANX or CHANY */ - for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { - t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); - /* 4. create edges between CHANX|CHANY and IPINs, using ipin2track_map */ - int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size(); - for (int iedge = 0; iedge < num_edges; ++iedge) { - int ipin_node_id = track2ipin_map[side_manager.to_size_t()][inode][iedge]; - /* add edges to the chan_node */ - add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, ipin_node_id, - rr_graph->rr_node[ipin_node_id].driver_switch); - } - /* 5. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */ - num_edges = track2track_map[side_manager.to_size_t()][inode].size(); - for (int iedge = 0; iedge < num_edges; ++iedge) { - int track_node_id = track2track_map[side_manager.to_size_t()][inode][iedge]; - /* add edges to the chan_node */ - add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, track_node_id, - rr_graph->rr_node[track_node_id].driver_switch); - } - } - } - - return; -} - -/************************************************************************ - * Convert the pin_to_track_map[0..nodes_per_chan-1][0..height][0..3][pin_numbers] - * to the existing routing resources in the General Switch Block (GSB) - * The resulting matrix will be oragnized in - * pin2track_map[gsb_side][0..chan_width-1][ipin_indices] - ***********************************************************************/ -static -t_pin2track_map build_gsb_pin_to_track_map(const RRGSB& rr_gsb, - std::vector< std::vector > grids, - int** Fc, - bool is_Fc_out, - int***** pin_to_track_map) { - /* [0..gsb_side][0..num_tracks][0..Fc-1] */ - t_pin2track_map pin2track_map; - /* Resize the matrix */ - pin2track_map.resize(rr_gsb.get_num_sides()); - - /* Walk through each side */ - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); - /* Get channel width and resize the matrix */ - size_t chan_width = rr_gsb.get_chan_width(gsb_side); - pin2track_map[side].resize(chan_width); - /* Find the ipin/opin nodes */ - size_t num_pin_nodes; - if (true == is_Fc_out) { /* Fc_out, we consider OPINs */ - num_pin_nodes = rr_gsb.get_num_opin_nodes(gsb_side); - } else { /* Fc_in, we consider IPINs */ - num_pin_nodes = rr_gsb.get_num_ipin_nodes(gsb_side); - } - for (size_t inode = 0; inode < num_pin_nodes; ++inode) { - t_rr_node* pin_node; - if (true == is_Fc_out) { /* Fc_out, we consider OPINs */ - pin_node = rr_gsb.get_opin_node(gsb_side, inode); - } else { /* Fc_in, we consider IPINs */ - pin_node = rr_gsb.get_ipin_node(gsb_side, inode); - } - /* For each IPIN, we find the type_descriptor, offset and pin_side on the grid */ - int grid_type_id = grids[pin_node->xlow][pin_node->ylow].type->index; - int offset = grid[pin_node->xlow][pin_node->ylow].offset; - enum e_side pin_side; - if (true == is_Fc_out) { /* Fc_out, we consider OPINs */ - pin_side = rr_gsb.get_opin_node_grid_side(gsb_side, inode); - } else { /* Fc_in, we consider IPINs */ - pin_side = rr_gsb.get_ipin_node_grid_side(gsb_side, inode); - } - /* Now, we fill the return matrix */ - /* Bypass empty array */ - if (NULL == pin_to_track_map[grid_type_id][pin_node->ptc_num][offset][0]) { - continue; - } - /* Get each track_id */ - for (int iconn = 0; iconn < Fc[grid_type_id][pin_node->ptc_num]; ++iconn) { - int track_id = pin_to_track_map[grid_type_id][pin_node->ptc_num][offset][pin_side][iconn]; - pin2track_map[gsb_side][track_id].push_back(inode); - } - } - } - - return pin2track_map; -} - -/************************************************************************ - * Build the track_to_ipin_map[gsb_side][0..chan_width-1][ipin_indices] - * based on the existing routing resources in the General Switch Block (GSB) - * This function supports both X-directional and Y-directional tracks - * The mapping is done in the following steps: - * 1. build a list of routing tracks which are allowed for connections - * We will check the Connection Block (CB) population of each routing track. - * By comparing current chan_y - ylow, we can determine if a CB connection - * is required for each routing track - * 2. Divide the routing tracks by segment types, so that we can balance - * the connections between IPINs and different types of routing tracks. - * 3. Scale the Fc of each pin to the actual number of routing tracks - * actual_Fc = (int) Fc * num_tracks / chan_width - * 4. Build ipin_to_track_map[gsb_side][0..num_ipin_nodes-1][track_indices] - * For each IPIN, we ensure at least one connection to the tracks. - * Then, we assign IPINs to tracks evenly while satisfying the actual_Fc - * 5. Convert the ipin_to_track_map to track_to_ipin_map - ***********************************************************************/ - -/************************************************************************ - * Build the opin_to_track_map[gsb_side][0..num_opin_nodes-1][track_indices] - * based on the existing routing resources in the General Switch Block (GSB) - * This function supports both X-directional and Y-directional tracks - * The mapping is done in the following steps: - * 1. Build a list of routing tracks whose starting points locate at this GSB - * (xlow - gsb_x == 0) - * 2. Divide the routing tracks by segment types, so that we can balance - * the connections between OPINs and different types of routing tracks. - * 3. Scale the Fc of each pin to the actual number of routing tracks - * actual_Fc = (int) Fc * num_tracks / chan_width - ***********************************************************************/ - -/************************************************************************ - * Add all direct clb-pin-to-clb-pin edges to given opin - ***********************************************************************/ -static -void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, - const DeviceCoordinator& device_size, - const DeviceCoordinator& from_grid_coordinator, - const t_grid_tile& from_grid, - const int delayless_switch, - const int num_directs, - const t_direct_inf *directs, - const t_clb_to_clb_directs *clb_to_clb_directs) { - t_type_ptr grid_type = from_grid.type; - - /* Iterate through all direct connections */ - for (int i = 0; i < num_directs; ++i) { - /* Bypass unmatched direct clb-to-clb connections */ - if (grid_type != clb_to_clb_directs[i].from_clb_type) { - continue; - } - bool swap; - int max_index, min_index; - /* Compute index of opin with regards to given pins */ - if ( clb_to_clb_directs[i].from_clb_pin_start_index - > clb_to_clb_directs[i].from_clb_pin_end_index) { - swap = true; - max_index = clb_to_clb_directs[i].from_clb_pin_start_index; - min_index = clb_to_clb_directs[i].from_clb_pin_end_index; - } else { - swap = false; - min_index = clb_to_clb_directs[i].from_clb_pin_start_index; - max_index = clb_to_clb_directs[i].from_clb_pin_end_index; - } - /* get every opin in the range */ - for (int opin = min_index; opin <= max_index; ++opin) { - int offset = opin - min_index; - /* This opin is specified to connect directly to an ipin, now compute which ipin to connect to */ - DeviceCoordinator to_grid_coordinator(from_grid_coordinator.get_x() + directs[i].x_offset, - from_grid_coordinator.get_y() + directs[i].y_offset); - if ( (to_grid_coordinator.get_x() < device_size.get_x() - 1) - && (to_grid_coordinator.get_y() < device_size.get_y() - 1) ) { - int ipin = OPEN; - if ( clb_to_clb_directs[i].to_clb_pin_start_index - > clb_to_clb_directs[i].to_clb_pin_end_index) { - if (true == swap) { - ipin = clb_to_clb_directs[i].to_clb_pin_end_index + offset; - } else { - ipin = clb_to_clb_directs[i].to_clb_pin_start_index - offset; - } - } else { - if(true == swap) { - ipin = clb_to_clb_directs[i].to_clb_pin_end_index - offset; - } else { - ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset; - } - } - /* Get the pin index in the rr_graph */ - int from_grid_ofs = from_grid.offset; - int to_grid_ofs = grid[to_grid_coordinator.get_x()][to_grid_coordinator.get_y()].offset; - int opin_node_id = get_rr_node_index(from_grid_coordinator.get_x(), - from_grid_coordinator.get_y() - from_grid_ofs, - OPIN, opin, rr_graph->rr_node_indices); - int ipin_node_id = get_rr_node_index(to_grid_coordinator.get_x(), - to_grid_coordinator.get_y() - to_grid_ofs, - IPIN, ipin, rr_graph->rr_node_indices); - /* add edges to the opin_node */ - add_one_edge_for_two_rr_nodes(rr_graph, opin_node_id, ipin_node_id, - delayless_switch); - } - } - } - - return; -} - - /************************************************************************ * Build the edges of each rr_node tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure @@ -1640,12 +984,11 @@ void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, static void build_rr_graph_edges(t_rr_graph* rr_graph, const DeviceCoordinator& device_size, - std::vector< std::vector > grids, - std::vector device_chan_width, - std::vector segment_inf, + const std::vector< std::vector > grids, + const std::vector device_chan_width, + const std::vector segment_inf, int** Fc_in, int** Fc_out, - int***** ipin_to_track_map, int***** opin_to_track_map, - enum e_switch_block_type sb_type, int Fs) { + const enum e_switch_block_type sb_type, const int Fs) { DeviceCoordinator device_range(device_size.get_x() - 1, device_size.get_y() - 1); @@ -1657,13 +1000,19 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, /* Create a GSB object */ RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); + DeviceCoordinator grid_coordinator = rr_gsb.get_grid_coordinator(); + /* adapt the track_to_ipin_lookup for the GSB nodes */ - t_pin2track_map ipin2track_map; /* [0..track_gsb_side][0..num_tracks][ipin_indices] */ - ipin2track_map = build_gsb_pin_to_track_map(rr_gsb, grids, Fc_in, false, ipin_to_track_map); + t_track2pin_map track2ipin_map; /* [0..track_gsb_side][0..num_tracks][ipin_indices] */ + /* Get the Fc index of the grid */ + int grid_Fc_in_index = grids[grid_coordinator.get_x()][grid_coordinator.get_x()].type->index; + track2ipin_map = build_gsb_track_to_ipin_map(rr_graph, rr_gsb, segment_inf, Fc_in[grid_Fc_in_index]); /* 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_pin_to_track_map(rr_gsb, grids, Fc_out, true, opin_to_track_map); + /* Get the Fc index of the grid */ + int grid_Fc_out_index = grids[grid_coordinator.get_x()][grid_coordinator.get_x()].type->index; + opin2track_map = build_gsb_opin_to_track_map(rr_graph, rr_gsb, segment_inf, Fc_out[grid_Fc_out_index]); /* adapt the switch_block_conn for the GSB nodes */ t_track2track_map sb_conn; /* [0..from_gsb_side][0..chan_width-1][track_indices] */ @@ -1671,7 +1020,7 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, /* Build edges for a GSB */ build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, - ipin2track_map, opin2track_map, + track2ipin_map, opin2track_map, sb_conn); /* Finish this GSB, go to the next*/ } @@ -1686,7 +1035,7 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, static void build_rr_graph_direct_connections(t_rr_graph* rr_graph, const DeviceCoordinator& device_size, - std::vector< std::vector > grids, + const std::vector< std::vector > grids, const int delayless_switch, const int num_directs, const t_direct_inf *directs, @@ -1702,7 +1051,7 @@ void build_rr_graph_direct_connections(t_rr_graph* rr_graph, continue; } DeviceCoordinator from_grid_coordinator(ix, iy); - build_direct_connections_for_one_gsb(rr_graph, device_size, + build_direct_connections_for_one_gsb(rr_graph, device_size, grids, from_grid_coordinator, grids[ix][iy], delayless_switch, @@ -1752,17 +1101,17 @@ void build_rr_graph_direct_connections(t_rr_graph* rr_graph, * a. cost_index * b. RC tree ***********************************************************************/ -void build_tileable_unidir_rr_graph(INP int L_num_types, - INP t_type_ptr types, INP int L_nx, INP int L_ny, - INP struct s_grid_tile **L_grid, INP int chan_width, - INP enum e_switch_block_type sb_type, INP int Fs, - INP int num_seg_types, - INP t_segment_inf * segment_inf, - INP int delayless_switch, - INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, - INP enum e_base_cost_type base_cost_type, - INP t_direct_inf *directs, - INP int num_directs, INP boolean ignore_Fc_0, +void build_tileable_unidir_rr_graph(INP const int L_num_types, + INP t_type_ptr types, INP const int L_nx, INP const int L_ny, + INP const struct s_grid_tile **L_grid, INP const int chan_width, + INP const enum e_switch_block_type sb_type, INP const int Fs, + INP const int num_seg_types, + INP const t_segment_inf * segment_inf, + INP const int num_switches, INP int const delayless_switch, const int global_route_switch, + INP const t_timing_inf timing_inf, INP int const wire_to_ipin_switch, + INP const enum e_base_cost_type base_cost_type, + INP const t_direct_inf *directs, + INP const int num_directs, INP const boolean ignore_Fc_0, OUTP int *Warnings) { /* Create an empty graph */ t_rr_graph rr_graph; @@ -1856,23 +1205,6 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; } - /* START IPINP MAP */ - /* Create ipin map lookups */ - int***** ipin_to_track_map = (int*****) my_calloc(L_num_types, sizeof(int****)); - boolean* perturb_ipins = alloc_and_load_perturb_ipins(chan_width, L_num_types, Fc_in, Fc_out, UNI_DIRECTIONAL); - for (int i = 0; i < L_num_types; ++i) { - ipin_to_track_map[i] = alloc_and_load_pin_to_track_map(RECEIVER, chan_width, Fc_in[i], &types[i], - perturb_ipins[i], UNI_DIRECTIONAL); - } - /* END IPINP MAP */ - - /* START OPINP MAP */ - /* Create opin map lookups */ - int***** opin_to_track_map = (int*****) my_calloc(L_num_types, sizeof(int****)); - for (int i = 0; i < L_num_types; ++i) { - opin_to_track_map[i] = alloc_and_load_pin_to_track_map(DRIVER, chan_width, Fc_out[i], &types[i], FALSE, UNI_DIRECTIONAL); - } - /************************************************************************ * 6. Build the connections tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure @@ -1884,7 +1216,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, /* Create edges for a tileable rr_graph */ build_rr_graph_edges(&rr_graph, device_size, grids, device_chan_width, segment_infs, - Fc_in, Fc_out, ipin_to_track_map, opin_to_track_map, + Fc_in, Fc_out, sb_type, Fs); /************************************************************************ @@ -1903,18 +1235,21 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, * a. cost_index * b. RC tree ***********************************************************************/ + /* We set global variables for rr_nodes here, they will be updated by rr_graph_external */ + num_rr_nodes = rr_graph.num_rr_nodes; + rr_node = rr_graph.rr_node; + rr_node_indices = rr_graph.rr_node_indices; + rr_graph_externals(timing_inf, segment_inf, num_seg_types, chan_width, wire_to_ipin_switch, base_cost_type); /************************************************************************ * 9. Sanitizer for the rr_graph, check connectivities of rr_nodes ***********************************************************************/ + check_rr_graph(GRAPH_UNIDIR_TILEABLE, types, L_nx, L_ny, chan_width, Fs, + num_seg_types, num_switches, segment_inf, global_route_switch, + delayless_switch, wire_to_ipin_switch, Fc_in, Fc_out); - /* We set global variables for rr_nodes here, - */ - num_rr_nodes = rr_graph.num_rr_nodes; - rr_node = rr_graph.rr_node; - rr_node_indices = rr_graph.rr_node_indices; /************************************************************************ * 10. Free all temp stucts @@ -1929,19 +1264,6 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, free_matrix(Fc_out,0, L_num_types, 0, sizeof(int)); Fc_out = NULL; } - if (perturb_ipins) { - free(perturb_ipins); - perturb_ipins = NULL; - } - if (opin_to_track_map) { - for (int i = 0; i < L_num_types; ++i) { - free_matrix4(opin_to_track_map[i], 0, types[i].num_pins - 1, 0, - types[i].height - 1, 0, 3, 0, sizeof(int)); - } - free(opin_to_track_map); - } - - free_type_pin_to_track_map(ipin_to_track_map, types); if(clb_to_clb_directs != NULL) { free(clb_to_clb_directs); } diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h index 26e1f9cc7..7f26867a1 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h @@ -1,15 +1,27 @@ #ifndef RR_GRAPH_TILEABLE_BUILDER_H #define RR_GRAPH_TILEABLE_BUILDER_H -void build_tileable_unidir_rr_graph(INP int L_num_types, - INP t_type_ptr types, INP int L_nx, INP int L_ny, - INP struct s_grid_tile **L_grid, INP int chan_width, - INP enum e_switch_block_type sb_type, INP int Fs, - INP int num_seg_types, - INP t_segment_inf * segment_inf, - INP int delayless_switch, - INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, - INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, - INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings); +#include + +#include "vpr_types.h" + +#include "chan_node_details.h" + +ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const size_t max_seg_length, + const enum e_side device_side, + const std::vector segment_inf); + +void build_tileable_unidir_rr_graph(INP const int L_num_types, + INP t_type_ptr types, INP const int L_nx, INP const int L_ny, + INP const struct s_grid_tile **L_grid, INP const int chan_width, + INP const enum e_switch_block_type sb_type, INP const int Fs, + INP const int num_seg_types, + INP const t_segment_inf * segment_inf, + INP const int num_switches, INP int const delayless_switch, const int global_route_switch, + INP const t_timing_inf timing_inf, INP int const wire_to_ipin_switch, + INP const enum e_base_cost_type base_cost_type, + INP const t_direct_inf *directs, + INP const int num_directs, INP const boolean ignore_Fc_0, + OUTP int *Warnings); #endif diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp new file mode 100755 index 000000000..e67e72e17 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp @@ -0,0 +1,1346 @@ +/********************************************************** + * MIT License + * + * Copyright (c) 2018 LNIS - The University of Utah + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ***********************************************************************/ + +/************************************************************************ + * Filename: rr_graph_tileable_gsb.cpp + * Created by: Xifan Tang + * Change history: + * +-------------------------------------+ + * | Date | Author | Notes + * +-------------------------------------+ + * | 2019/06/19 | Xifan Tang | Created + * +-------------------------------------+ + ***********************************************************************/ +/************************************************************************ + * This file contains a builder for track-to-track connections inside a + * tileable General Switch Block (GSB). + ***********************************************************************/ + +#include +#include + +#include +#include + +#include "vpr_types.h" +#include "rr_graph_util.h" +#include "rr_graph2.h" + +#include "rr_graph_tileable_gsb.h" +#include "rr_graph_tileable_builder.h" + +#include "fpga_x2p_backannotate_utils.h" + +#include "my_free_fwd.h" + +/************************************************************************ + * Internal data structures + ***********************************************************************/ +typedef std::vector> t_track_group; + +/************************************************************************ + * A enumeration to list the status of a track inside a GSB + * 1. start; 2. end; 3. passing + * This is used to group tracks which ease the building of + * track-to-track mapping matrix + ***********************************************************************/ +enum e_track_status { + TRACK_START, + TRACK_END, + TRACK_PASS, + NUM_TRACK_STATUS /* just a place holder to get the number of status */ +}; + +/************************************************************************ + * Check if a track starts from this GSB or not + * (xlow, ylow) should be same as the GSB side coordinator + * + * Check if a track ends at this GSB or not + * (xhigh, yhigh) should be same as the GSB side coordinator + ***********************************************************************/ +static +enum e_track_status determine_track_status_of_gsb(const RRGSB& rr_gsb, + const enum e_side gsb_side, + const size_t track_id) { + enum e_track_status track_status = TRACK_PASS; + /* Get the rr_node */ + t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); + /* Get the coordinators */ + DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); + + /* INC_DIRECTION start_track: (xlow, ylow) should be same as the GSB side coordinator */ + if ( ((size_t)track_node->xlow == side_coordinator.get_x()) + && ((size_t)track_node->ylow == side_coordinator.get_y()) + && (OUT_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { + /* Double check: start track should be an OUTPUT PORT of the GSB */ + track_status = TRACK_START; + } + /* INC_DIRECTION end_track: (xhigh, yhigh) should be same as the GSB side coordinator */ + if ( ((size_t)track_node->xhigh == side_coordinator.get_x()) + && ((size_t)track_node->yhigh == side_coordinator.get_y()) + && (IN_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { + /* Double check: end track should be an INPUT PORT of the GSB */ + track_status = TRACK_END; + } + + return track_status; +} + + +/************************************************************************ + * Check if the GSB is in the Connection Block (CB) population list of the segment + * SB population of a L4 wire: 1 0 0 1 + * + * +----+ +----+ +----+ +----+ + * | CB |--->| CB |--->| CB |--->| CB | + * +----+ +----+ +----+ +----+ + * Engage CB connection Yes No No Yes + * + * We will find the offset between gsb_side_coordinator and (xlow,ylow) of the track + * Use the offset to check if the tracks should engage in this GSB connection + ***********************************************************************/ +static +bool is_gsb_in_track_cb_population(const RRGSB& rr_gsb, + const enum e_side gsb_side, + const int track_id, + const std::vector segment_inf) { + /* Get the rr_node */ + t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); + /* Get the coordinators */ + DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); + + /* Get the offset */ + size_t offset = (side_coordinator.get_x() - track_node->xlow) + + (side_coordinator.get_y() - track_node->ylow); + + /* Get segment id */ + size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); + /* validate offset */ + assert (offset < (size_t)segment_inf[seg_id].cb_len); + + /* Get the SB population */ + bool in_cb_population = false; + if (TRUE == segment_inf[seg_id].cb[offset]) { + in_cb_population = true; + } + return in_cb_population; +} + +/************************************************************************ + * Check if the GSB is in the Switch Block (SB) population list of the segment + * SB population of a L3 wire: 1 0 0 1 + * + * +----+ +----+ +----+ +----+ + * | SB |--->| SB |--->| SB |--->| SB | + * +----+ +----+ +----+ +----+ + * Engage SB connection Yes No No Yes + * + * We will find the offset between gsb_side_coordinator and (xlow,ylow) of the track + * Use the offset to check if the tracks should engage in this GSB connection + ***********************************************************************/ +static +bool is_gsb_in_track_sb_population(const RRGSB& rr_gsb, + const enum e_side gsb_side, + const int track_id, + const std::vector segment_inf) { + /* Get the rr_node */ + t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); + /* Get the coordinators */ + DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); + + /* Get the offset */ + size_t offset = (side_coordinator.get_x() - track_node->xlow) + + (side_coordinator.get_y() - track_node->ylow); + + /* Get segment id */ + size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); + /* validate offset */ + assert (offset < (size_t)segment_inf[seg_id].sb_len); + + /* Get the SB population */ + bool in_sb_population = false; + if (TRUE == segment_inf[seg_id].sb[offset]) { + in_sb_population = true; + } + return in_sb_population; +} + +/************************************************************************ + * Create a list of track_id based on the to_track and num_to_tracks + * We consider the following list [to_track, to_track + Fs/3 - 1] + * if the [to_track + Fs/3 - 1] exceeds the num_to_tracks, we start over from 0! +***********************************************************************/ +static +std::vector get_to_track_list(const int Fs, const int to_track, const int num_to_tracks) { + std::vector to_tracks; + for (int i = 0; i < Fs; i = i + 3) { + /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied + * The optimal track selection should be done in a more scientific way!!! + */ + size_t to_track_i = to_track + i; + /* make sure the track id is still in range */ + if ( to_track_i > (size_t)num_to_tracks) { + to_track_i = to_track_i % num_to_tracks; + } + /* from track must be connected */ + to_tracks.push_back(to_track_i); + } + return to_tracks; +} + +/************************************************************************ + * This function aims to return the track indices that drive the from_track + * in a Switch Block + * The track_ids to return will depend on different topologies of SB + * SUBSET, UNIVERSAL, and WILTON. + ***********************************************************************/ +static +std::vector get_switch_block_to_track_id(const enum e_switch_block_type switch_block_type, + const int Fs, + const enum e_side from_side, + const int from_track, + const enum e_side to_side, + const int num_to_tracks) { + + /* This routine returns the track number to which the from_track should + * connect. It supports any Fs % 3 == 0, switch blocks. + */ + std::vector to_tracks; + + /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied + * The optimal track selection should be done in a more scientific way!!! + */ + + assert (0 == Fs % 3); + + switch (switch_block_type) { + case SUBSET: /* NB: Global routing uses SUBSET too */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + /* Finish, we return */ + return to_tracks; + case UNIVERSAL: + if ( (from_side == LEFT) + || (from_side == RIGHT) ) { + /* For the prev_side, to_track is from_track + * For the next_side, to_track is num_to_tracks - 1 - from_track + * For the opposite_side, to_track is always from_track + */ + Side side_manager(from_side); + if ( (to_side == side_manager.get_opposite()) + || (to_side == side_manager.get_rotate_counterclockwise()) ) { + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == side_manager.get_rotate_clockwise()) { + to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); + } + } + + if ( (from_side == TOP) + || (from_side == BOTTOM) ) { + /* For the next_side, to_track is from_track + * For the prev_side, to_track is num_to_tracks - 1 - from_track + * For the opposite_side, to_track is always from_track + */ + Side side_manager(from_side); + if ( (to_side == side_manager.get_opposite()) + || (to_side == side_manager.get_rotate_clockwise()) ) { + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == side_manager.get_rotate_counterclockwise()) { + to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); + } + } + /* Finish, we return */ + return to_tracks; + /* End switch_block_type == UNIVERSAL case. */ + case WILTON: + /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ + if (from_side == LEFT) { + if (to_side == RIGHT) { /* CHANX to CHANX */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == TOP) { /* from CHANX to CHANY */ + to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); + } else if (to_side == BOTTOM) { + to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); + } + } else if (from_side == RIGHT) { + if (to_side == LEFT) { /* CHANX to CHANX */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == TOP) { /* from CHANX to CHANY */ + to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); + } else if (to_side == BOTTOM) { + to_tracks = get_to_track_list(Fs, (num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); + } + } else if (from_side == BOTTOM) { + if (to_side == TOP) { /* CHANY to CHANY */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == LEFT) { /* from CHANY to CHANX */ + to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); + } else if (to_side == RIGHT) { + to_tracks = get_to_track_list(Fs, (2 * num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); + } + } else if (from_side == TOP) { + if (to_side == BOTTOM) { /* CHANY to CHANY */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == LEFT) { /* from CHANY to CHANX */ + to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); + } else if (to_side == RIGHT) { + to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); + } + } + /* Finish, we return */ + return to_tracks; + /* End switch_block_type == WILTON case. */ + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid switch block pattern !\n", + __FILE__, __LINE__); + exit(1); + } + + return to_tracks; +} + + +/************************************************************************ + * Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices] + * For a group of from_track nodes and to_track nodes + * For each side of from_tracks, we call a routine to get the list of to_tracks + * Then, we fill the track2track_map + ***********************************************************************/ +static +void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_switch_block_type sb_type, + const int Fs, + const t_track_group from_tracks, /* [0..gsb_side][track_indices] */ + const t_track_group to_tracks, /* [0..gsb_side][track_indices] */ + t_track2track_map* track2track_map) { + for (size_t side = 0; side < from_tracks.size(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* Find the other sides where the start tracks will locate */ + std::vector to_track_sides; + /* 0. opposite side */ + to_track_sides.push_back(side_manager.get_opposite()); + /* 1. prev side */ + /* Previous side definition: TOP => LEFT; RIGHT=>TOP; BOTTOM=>RIGHT; LEFT=>BOTTOM */ + to_track_sides.push_back(side_manager.get_rotate_counterclockwise()); + /* 2. next side */ + /* Next side definition: TOP => RIGHT; RIGHT=>BOTTOM; BOTTOM=>LEFT; LEFT=>TOP */ + to_track_sides.push_back(side_manager.get_rotate_clockwise()); + + for (size_t inode = 0; inode < from_tracks[side].size(); ++inode) { + for (size_t to_side_id = 0; to_side_id < to_track_sides.size(); ++to_side_id) { + enum e_side to_side = to_track_sides[to_side_id]; + Side to_side_manager(to_side); + size_t to_side_index = to_side_manager.to_size_t(); + /* Bypass those to_sides have no nodes */ + if (0 == to_tracks[to_side_index].size()) { + continue; + } + /* Get other track_ids depending on the switch block pattern */ + /* Find the track ids that will start at the other sides */ + std::vector to_track_ids = get_switch_block_to_track_id(sb_type, Fs, gsb_side, inode, + to_side, + to_tracks[to_side_index].size()); + /* Update the track2track_map: */ + for (size_t to_track_id = 0; to_track_id < to_track_ids.size(); ++to_track_id) { + size_t from_side_index = side_manager.to_size_t(); + size_t from_track_index = from_tracks[side][inode]; + size_t to_track_index = to_tracks[to_side_index][to_track_ids[to_track_id]]; + t_rr_node* to_track_node = rr_gsb.get_chan_node(to_side, to_track_index); + (*track2track_map)[from_side_index][from_track_index].push_back(to_track_node - rr_graph->rr_node); + } + } + } + } + + return; +} + +/************************************************************************ + * Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices] + * based on the existing routing resources in the General Switch Block (GSB) + * The track_indices is the indices of tracks that the node at from_side and [0..chan_width-1] will drive + * IMPORTANT: the track_indices are the indicies in the GSB context, but not the rr_graph!!! + * We separate the connections into two groups: + * Group 1: the routing tracks start from this GSB + * We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON) + * Group 2: the routing tracks do not start from this GSB (bypassing wires) + * We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON) + * but we will check the Switch Block (SB) population of these + * routing segments, and determine which requires connections + * + * CHANY CHANY CHANY CHANY + * [0] [1] [2] [3] + * start yes no yes no + * end +-------------------------+ start Group 1 Group 2 + * no CHANX[0] | TOP | CHANX[0] yes TOP/BOTTOM TOP/BOTTOM + * | | CHANY[0,2] CHANY[1,3] + * yes CHANX[1] | | CHANX[1] no + * | LEFT RIGHT | + * no CHANX[2] | | CHANX[2] yes + * | | + * yes CHANX[3] | BOTTOM | CHANX[3] no + * +-------------------------+ + * CHANY CHANY CHANY CHANY + * [0] [1] [2] [3] + * start yes no yes no + * + * The mapping is done in the following steps: (For each side of the GSB) + * 1. Build a list of tracks that will start from this side + * if a track starts, its xlow/ylow is the same as the x,y of this gsb + * 2. Build a list of tracks on the other sides belonging to Group 1. + * Take the example of RIGHT side, we will collect + * a. tracks that will end at the LEFT side + * b. tracks that will start at the TOP side + * c. tracks that will start at the BOTTOM side + * 3. Apply switch block patterns to Group 1 (SUBSET, UNIVERSAL, WILTON) + * 4. Build a list of tracks on the other sides belonging to Group 1. + * Take the example of RIGHT side, we will collect + * a. tracks that will bypass at the TOP side + * b. tracks that will bypass at the BOTTOM side + * 5. Apply switch block patterns to Group 2 (SUBSET, UNIVERSAL, WILTON) + ***********************************************************************/ +t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_switch_block_type sb_type, + const int Fs, + const std::vector segment_inf) { + t_track2track_map track2track_map; /* [0..gsb_side][0..chan_width][track_indices] */ + + /* Categorize tracks into 3 groups: + * (1) tracks will start here + * (2) tracks will end here + * (2) tracks will just pass through the SB */ + t_track_group start_tracks; /* [0..gsb_side][track_indices] */ + t_track_group end_tracks; /* [0..gsb_side][track_indices] */ + t_track_group pass_tracks; /* [0..gsb_side][track_indices] */ + + /* resize to the number of sides */ + start_tracks.resize(rr_gsb.get_num_sides()); + end_tracks.resize(rr_gsb.get_num_sides()); + pass_tracks.resize(rr_gsb.get_num_sides()); + + /* Walk through each side */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* Build a list of tracks that will start from this side */ + for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { + /* check if this track will start from here */ + enum e_track_status track_status = determine_track_status_of_gsb(rr_gsb, gsb_side, inode); + switch (track_status) { + case TRACK_START: + /* update starting track list */ + start_tracks[gsb_side].push_back(inode); + break; + case TRACK_END: + /* Update end track list */ + end_tracks[gsb_side].push_back(inode); + break; + case TRACK_PASS: + /* We need to check Switch block population of this track + * The track node will not be considered if there supposed to be no SB at this position + */ + if (true == is_gsb_in_track_sb_population(rr_gsb, gsb_side, inode, segment_inf)) { + /* Update passing track list */ + pass_tracks[gsb_side].push_back(inode); + } + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid track status!\n", + __FILE__, __LINE__); + exit(1); + } + } + } + + /* Allocate track2track map */ + track2track_map.resize(rr_gsb.get_num_sides()); + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* allocate track2track_map[gsb_side] */ + track2track_map[side].resize(rr_gsb.get_chan_width(gsb_side)); + for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { + /* allocate track2track_map[gsb_side][inode] */ + track2track_map[side][inode].clear(); + } + } + + /* For Group 1: we build connections between end_tracks and start_tracks*/ + build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb, + sb_type, Fs, + end_tracks, start_tracks, + &track2track_map); + + /* For Group 2: we build connections between end_tracks and start_tracks*/ + /* Currently, I use the same Switch Block pattern for the passing tracks and end tracks, + * TODO: This can be improved with different patterns! + */ + build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb, + sb_type, Fs, + pass_tracks, start_tracks, + &track2track_map); + + return track2track_map; +} + +/* Build a RRChan Object with the given channel type and coorindators */ +static +RRChan build_one_tileable_rr_chan(const DeviceCoordinator& chan_coordinator, + const t_rr_type chan_type, + const t_rr_graph* rr_graph, + const ChanNodeDetails& chan_details) { + int chan_width = 0; + t_rr_node** chan_rr_nodes = NULL; + + /* Create a rr_chan object and check if it is unique in the graph */ + RRChan rr_chan; + /* Fill the information */ + rr_chan.set_type(chan_type); + + /* Collect rr_nodes for this channel */ + chan_rr_nodes = get_chan_rr_nodes(&chan_width, chan_type, chan_coordinator.get_x(), chan_coordinator.get_y(), + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + + /* Reserve */ + /* rr_chan.reserve_node(size_t(chan_width)); */ + + /* Fill the rr_chan */ + for (size_t itrack = 0; itrack < size_t(chan_width); ++itrack) { + size_t iseg = chan_details.get_track_segment_id(itrack); + rr_chan.add_node(chan_rr_nodes[itrack], iseg); + } + + /* Free rr_nodes */ + my_free(chan_rr_nodes); + + return rr_chan; +} + +/*********************************************************************** + * Build a General Switch Block (GSB) + * which includes: + * [I] A Switch Box subckt consists of following ports: + * 1. Channel Y [x][y] inputs + * 2. Channel X [x+1][y] inputs + * 3. Channel Y [x][y-1] outputs + * 4. Channel X [x][y] outputs + * 5. Grid[x][y+1] Right side outputs pins + * 6. Grid[x+1][y+1] Left side output pins + * 7. Grid[x+1][y+1] Bottom side output pins + * 8. Grid[x+1][y] Top side output pins + * 9. Grid[x+1][y] Left side output pins + * 10. Grid[x][y] Right side output pins + * 11. Grid[x][y] Top side output pins + * 12. Grid[x][y+1] Bottom side output pins + * + * -------------- -------------- + * | | CBY | | + * | Grid | ChanY | Grid | + * | [x][y+1] | [x][y+1] | [x+1][y+1] | + * | | | | + * -------------- -------------- + * ---------- + * ChanX & CBX | Switch | ChanX + * [x][y] | Box | [x+1][y] + * | [x][y] | + * ---------- + * -------------- -------------- + * | | | | + * | Grid | ChanY | Grid | + * | [x][y] | [x][y] | [x+1][y] | + * | | | | + * -------------- -------------- + * For channels chanY with INC_DIRECTION on the top side, they should be marked as outputs + * For channels chanY with DEC_DIRECTION on the top side, they should be marked as inputs + * For channels chanY with INC_DIRECTION on the bottom side, they should be marked as inputs + * For channels chanY with DEC_DIRECTION on the bottom side, they should be marked as outputs + * For channels chanX with INC_DIRECTION on the left side, they should be marked as inputs + * For channels chanX with DEC_DIRECTION on the left side, they should be marked as outputs + * For channels chanX with INC_DIRECTION on the right side, they should be marked as outputs + * For channels chanX with DEC_DIRECTION on the right side, they should be marked as inputs + * + * [II] A X-direction Connection Block [x][y] + * The connection block shares the same routing channel[x][y] with the Switch Block + * We just need to fill the ipin nodes at TOP and BOTTOM sides + * as well as properly fill the ipin_grid_side information + * [III] A Y-direction Connection Block [x][y+1] + * The connection block shares the same routing channel[x][y+1] with the Switch Block + * We just need to fill the ipin nodes at LEFT and RIGHT sides + * as well as properly fill the ipin_grid_side information + ***********************************************************************/ +RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, + const std::vector device_chan_width, + const std::vector segment_inf, + const DeviceCoordinator& gsb_coordinator, + t_rr_graph* rr_graph) { + /* Create an object to return */ + RRGSB rr_gsb; + + /* Check */ + assert(gsb_coordinator.get_x() <= device_range.get_x()); + assert(gsb_coordinator.get_y() <= device_range.get_y()); + + /* Coordinator initialization */ + rr_gsb.set_coordinator(gsb_coordinator.get_x(), gsb_coordinator.get_y()); + + /* Basic information*/ + rr_gsb.init_num_sides(4); /* Fixed number of sides */ + + /* Find all rr_nodes of channels */ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + /* Local variables inside this for loop */ + Side side_manager(side); + DeviceCoordinator coordinator = rr_gsb.get_side_block_coordinator(side_manager.get_side()); + RRChan rr_chan; + int temp_num_opin_rr_nodes[2] = {0,0}; + t_rr_node** temp_opin_rr_node[2] = {NULL, NULL}; + enum e_side opin_grid_side[2] = {NUM_SIDES, NUM_SIDES}; + enum PORTS chan_dir_to_port_dir_mapping[2] = {OUT_PORT, IN_PORT}; /* 0: INC_DIRECTION => ?; 1: DEC_DIRECTION => ? */ + /* 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], device_range.get_x() - 1, + NUM_SIDES, segment_inf); + ChanNodeDetails chany_details = build_unidir_chan_node_details(device_chan_width[1], device_range.get_y() - 1, + NUM_SIDES, segment_inf); + + switch (side) { + case TOP: /* TOP = 0 */ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_y() == device_range.get_y()) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANY, rr_graph, chany_details); + chan_dir_to_port_dir_mapping[0] = OUT_PORT; /* INC_DIRECTION => OUT_PORT */ + chan_dir_to_port_dir_mapping[1] = IN_PORT; /* DEC_DIRECTION => IN_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* Include Grid[x][y+1] RIGHT side outputs pins */ + temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], + OPIN, gsb_coordinator.get_x(), gsb_coordinator.get_y() + 1, 1, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* Include Grid[x+1][y+1] Left side output pins */ + temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], + OPIN, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y() + 1, 3, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + + /* Assign grid side of OPIN */ + /* Grid[x][y+1] RIGHT side outputs pins */ + opin_grid_side[0] = RIGHT; + /* Grid[x+1][y+1] left side outputs pins */ + opin_grid_side[1] = LEFT; + break; + case RIGHT: /* RIGHT = 1 */ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_x() == device_range.get_x()) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for top: chany[x][y+1] */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANX, rr_graph, chanx_details); + chan_dir_to_port_dir_mapping[0] = OUT_PORT; /* INC_DIRECTION => OUT_PORT */ + chan_dir_to_port_dir_mapping[1] = IN_PORT; /* DEC_DIRECTION => IN_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* include Grid[x+1][y+1] Bottom side output pins */ + temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], + OPIN, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y() + 1, 2, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* include Grid[x+1][y] Top side output pins */ + temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], + OPIN, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y(), 0, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* Assign grid side of OPIN */ + /* Grid[x+1][y+1] BOTTOM side outputs pins */ + opin_grid_side[0] = BOTTOM; + /* Grid[x+1][y] TOP side outputs pins */ + opin_grid_side[1] = TOP; + break; + case BOTTOM: /* BOTTOM = 2*/ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_y() == 0) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for bottom: chany[x][y] */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANY, rr_graph, chany_details); + chan_dir_to_port_dir_mapping[0] = IN_PORT; /* INC_DIRECTION => IN_PORT */ + chan_dir_to_port_dir_mapping[1] = OUT_PORT; /* DEC_DIRECTION => OUT_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* include Grid[x+1][y] Left side output pins */ + temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], + OPIN, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y(), 3, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* include Grid[x][y] Right side output pins */ + temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], + OPIN, gsb_coordinator.get_x(), gsb_coordinator.get_y(), 1, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* Assign grid side of OPIN */ + /* Grid[x+1][y] LEFT side outputs pins */ + opin_grid_side[0] = LEFT; + /* Grid[x][y] RIGHT side outputs pins */ + opin_grid_side[1] = RIGHT; + break; + case LEFT: /* LEFT = 3 */ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_x() == 0) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for left: chanx[x][y] */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANX, rr_graph, chanx_details); + chan_dir_to_port_dir_mapping[0] = IN_PORT; /* INC_DIRECTION => IN_PORT */ + chan_dir_to_port_dir_mapping[1] = OUT_PORT; /* DEC_DIRECTION => OUT_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* include Grid[x][y+1] Bottom side outputs pins */ + temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], + OPIN, gsb_coordinator.get_x(), gsb_coordinator.get_y() + 1, 2, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* include Grid[x][y] Top side output pins */ + temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], + OPIN, gsb_coordinator.get_x(), gsb_coordinator.get_y(), 0, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + + /* Grid[x][y+1] BOTTOM side outputs pins */ + opin_grid_side[0] = BOTTOM; + /* Grid[x][y] TOP side outputs pins */ + opin_grid_side[1] = TOP; + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid side index!\n", + __FILE__, __LINE__); + exit(1); + } + + /* Organize a vector of port direction */ + if (0 < rr_chan.get_chan_width()) { + std::vector rr_chan_dir; + rr_chan_dir.resize(rr_chan.get_chan_width()); + for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) { + /* Identify the directionality, record it in rr_node_direction */ + if (INC_DIRECTION == rr_chan.get_node(itrack)->direction) { + rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[0]; + } else { + assert (DEC_DIRECTION == rr_chan.get_node(itrack)->direction); + rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[1]; + } + } + /* Fill chan_rr_nodes */ + rr_gsb.add_chan_node(side_manager.get_side(), rr_chan, rr_chan_dir); + } + + /* Fill opin_rr_nodes */ + /* Copy from temp_opin_rr_node to opin_rr_node */ + for (int inode = 0; inode < temp_num_opin_rr_nodes[0]; ++inode) { + /* Grid[x+1][y+1] Bottom side outputs pins */ + rr_gsb.add_opin_node(temp_opin_rr_node[0][inode], side_manager.get_side(), opin_grid_side[0]); + } + for (int inode = 0; inode < temp_num_opin_rr_nodes[1]; ++inode) { + /* Grid[x+1][y] TOP side outputs pins */ + rr_gsb.add_opin_node(temp_opin_rr_node[1][inode], side_manager.get_side(), opin_grid_side[1]); + } + + /* Clean ipin_rr_nodes */ + /* We do not have any IPIN for a Switch Block */ + rr_gsb.clear_ipin_nodes(side_manager.get_side()); + + /* Free */ + temp_num_opin_rr_nodes[0] = 0; + my_free(temp_opin_rr_node[0]); + temp_num_opin_rr_nodes[1] = 0; + my_free(temp_opin_rr_node[1]); + /* Set them to NULL, avoid double free errors */ + temp_opin_rr_node[0] = NULL; + temp_opin_rr_node[1] = NULL; + opin_grid_side[0] = NUM_SIDES; + opin_grid_side[1] = NUM_SIDES; + } + + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + /* Local variables inside this for loop */ + Side side_manager(side); + size_t ix; + size_t iy; + enum e_side chan_side; + int num_temp_ipin_rr_nodes = 0; + t_rr_node** temp_ipin_rr_node = NULL; + enum e_side ipin_rr_node_grid_side; + + switch (side) { + case TOP: /* TOP = 0 */ + /* For the bording, we should take special care */ + /* Check if left side chan width is 0 or not */ + chan_side = LEFT; + /* Build the connection block: ipin and ipin_grid_side */ + /* BOTTOM side INPUT Pins of Grid[x][y+1] */ + ix = rr_gsb.get_sb_x(); + iy = rr_gsb.get_sb_y() + 1; + ipin_rr_node_grid_side = BOTTOM; + break; + case RIGHT: /* RIGHT = 1 */ + /* For the bording, we should take special care */ + /* Check if TOP side chan width is 0 or not */ + chan_side = TOP; + /* Build the connection block: ipin and ipin_grid_side */ + /* LEFT side INPUT Pins of Grid[x+1][y+1] */ + ix = rr_gsb.get_sb_x() + 1; + iy = rr_gsb.get_sb_y() + 1; + ipin_rr_node_grid_side = LEFT; + break; + case BOTTOM: /* BOTTOM = 2*/ + /* For the bording, we should take special care */ + /* Check if left side chan width is 0 or not */ + chan_side = LEFT; + /* Build the connection block: ipin and ipin_grid_side */ + /* TOP side INPUT Pins of Grid[x][y] */ + ix = rr_gsb.get_sb_x(); + iy = rr_gsb.get_sb_y(); + ipin_rr_node_grid_side = TOP; + break; + case LEFT: /* LEFT = 3 */ + /* For the bording, we should take special care */ + /* Check if left side chan width is 0 or not */ + chan_side = TOP; + /* Build the connection block: ipin and ipin_grid_side */ + /* RIGHT side INPUT Pins of Grid[x][y+1] */ + ix = rr_gsb.get_sb_x(); + iy = rr_gsb.get_sb_y() + 1; + ipin_rr_node_grid_side = RIGHT; + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid side index!\n", + __FILE__, __LINE__); + exit(1); + } + + /* If there is no channel at this side, we skip ipin_node annotation */ + if (0 == rr_gsb.get_chan_width(chan_side)) { + continue; + } + /* Collect IPIN rr_nodes*/ + temp_ipin_rr_node = get_grid_side_pin_rr_nodes(&(num_temp_ipin_rr_nodes), + IPIN, ix, iy, ipin_rr_node_grid_side, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* Fill the ipin nodes of RRGSB */ + for (int inode = 0; inode < num_temp_ipin_rr_nodes; ++inode) { + rr_gsb.add_ipin_node(temp_ipin_rr_node[inode], side_manager.get_side(), ipin_rr_node_grid_side); + } + /* Free */ + num_temp_ipin_rr_nodes = 0; + my_free(temp_ipin_rr_node); + } + + return rr_gsb; +} + +/************************************************************************ + * Add a edge connecting two rr_nodes + * For src rr_node, update the edge list and update switch_id, + * For des rr_node, update the fan_in + ***********************************************************************/ +static +void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, + const int src_rr_node_id, + const int des_rr_node_id, + const short switch_id) { + /* Check */ + assert ( (-1 < src_rr_node_id) && (src_rr_node_id < rr_graph->num_rr_nodes) ); + assert ( (-1 < des_rr_node_id) && (des_rr_node_id < rr_graph->num_rr_nodes) ); + + t_rr_node* src_rr_node = &(rr_graph->rr_node[src_rr_node_id]); + t_rr_node* des_rr_node = &(rr_graph->rr_node[des_rr_node_id]); + + /* Allocate edge and switch to src_rr_node */ + src_rr_node->num_edges++; + if (NULL == src_rr_node->edges) { + /* calloc */ + src_rr_node->edges = (int*) my_calloc( src_rr_node->num_edges, sizeof(int) ); + src_rr_node->switches = (short*) my_calloc( src_rr_node->num_edges, sizeof(short) ); + } else { + /* realloc */ + src_rr_node->edges = (int*) my_realloc(src_rr_node->edges, + src_rr_node->num_edges * sizeof(int)); + src_rr_node->switches = (short*) my_realloc(src_rr_node->switches, + src_rr_node->num_edges * sizeof(short)); + } + /* Fill edge and switch info */ + src_rr_node->edges[src_rr_node->num_edges - 1] = des_rr_node_id; + src_rr_node->switches[src_rr_node->num_edges - 1] = switch_id; + + /* Update the des_rr_node */ + des_rr_node->fan_in++; + + return; +} + +/************************************************************************ + * Create edges for each rr_node of a General Switch Blocks (GSB): + * 1. create edges between SOURCE and OPINs + * 2. create edges between IPINs and SINKs + * 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) + * 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) + * 5. create edges between OPINs and IPINs (direct-connections) + ***********************************************************************/ +void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, const RRGSB* rr_gsb, + const t_track2pin_map track2ipin_map, + const t_pin2track_map opin2track_map, + const t_track2track_map track2track_map) { + /* Check rr_gsb */ + assert (NULL != rr_gsb); + + /* Walk through each sides */ + for (size_t side = 0; side < rr_gsb->get_num_sides(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + + /* Find OPINs */ + for (size_t inode = 0; inode < rr_gsb->get_num_opin_nodes(gsb_side); ++inode) { + t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode); + /* 1. create edges between SOURCE and OPINs */ + int src_node_id = get_rr_node_index(opin_node->xlow, opin_node->ylow, + SOURCE, opin_node->ptc_num, + rr_graph->rr_node_indices); + /* add edges to the src_node */ + add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, opin_node - rr_graph->rr_node, + opin_node->driver_switch); + /* 2. create edges between OPINs and CHANX|CHANY, using opin2track_map */ + int num_edges = opin2track_map[side_manager.to_size_t()][inode].size(); + for (int iedge = 0; iedge < num_edges; ++iedge) { + int track_node_id = opin2track_map[side_manager.to_size_t()][inode][iedge]; + /* add edges to the chan_node */ + add_one_edge_for_two_rr_nodes(rr_graph, opin_node - rr_graph->rr_node, track_node_id, + rr_graph->rr_node[track_node_id].driver_switch); + } + } + + /* Find IPINs */ + for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) { + t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode); + /* 3. create edges between IPINs and SINKs */ + int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow, + SINK, ipin_node->ptc_num, + rr_graph->rr_node_indices); + /* add edges to connect the IPIN node to SINK nodes */ + add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id, + rr_graph->rr_node[sink_node_id].driver_switch); + } + /* Find CHANX or CHANY */ + for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { + t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); + /* 4. create edges between CHANX|CHANY and IPINs, using ipin2track_map */ + int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size(); + for (int iedge = 0; iedge < num_edges; ++iedge) { + int ipin_node_id = track2ipin_map[side_manager.to_size_t()][inode][iedge]; + /* add edges to the chan_node */ + add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, ipin_node_id, + rr_graph->rr_node[ipin_node_id].driver_switch); + } + /* 5. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */ + num_edges = track2track_map[side_manager.to_size_t()][inode].size(); + for (int iedge = 0; iedge < num_edges; ++iedge) { + int track_node_id = track2track_map[side_manager.to_size_t()][inode][iedge]; + /* add edges to the chan_node */ + add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, track_node_id, + rr_graph->rr_node[track_node_id].driver_switch); + } + } + } + + return; +} + +/************************************************************************ + * Build track2ipin_map for an IPIN + * 1. build a list of routing tracks which are allowed for connections + * We will check the Connection Block (CB) population of each routing track. + * By comparing current chan_y - ylow, we can determine if a CB connection + * is required for each routing track + * 2. Divide the routing tracks by segment types, so that we can balance + * the connections between IPINs and different types of routing tracks. + * 3. Scale the Fc of each pin to the actual number of routing tracks + * actual_Fc = (int) Fc * num_tracks / chan_width + ***********************************************************************/ +static +void build_gsb_one_ipin_track2pin_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_side ipin_side, + const size_t ipin_node_id, + const size_t Fc, + const size_t offset, + const std::vector segment_inf, + t_track2pin_map* track2ipin_map) { + /* Get a list of segment_ids*/ + enum e_side chan_side = rr_gsb.get_cb_chan_side(ipin_side); + std::vector seg_list = rr_gsb.get_chan_segment_ids(chan_side); + size_t chan_width = rr_gsb.get_chan_width(chan_side); + Side ipin_side_manager(ipin_side); + t_rr_node* ipin_node = rr_gsb.get_ipin_node(ipin_side, ipin_node_id); + + for (size_t iseg = 0; iseg < seg_list.size(); ++iseg) { + /* Get a list of node that have the segment id */ + std::vector track_list = rr_gsb.get_chan_node_ids_by_segment_ids(chan_side, seg_list[iseg]); + /* Refine the track_list: keep those will have connection blocks in the GSB */ + std::vector actual_track_list; + for (size_t inode = 0; inode < track_list.size(); ++inode) { + /* Check if tracks allow connection blocks in the GSB*/ + if (false == is_gsb_in_track_cb_population(rr_gsb, chan_side, track_list[inode], segment_inf)) { + continue; /* Bypass condition */ + } + /* Push the node to actual_track_list */ + actual_track_list.push_back(track_list[inode]); + } + /* Check the actual track list */ + assert (0 == actual_track_list.size() % 2); + + /* Scale Fc */ + int actual_Fc = Fc * (float)(actual_track_list.size() / chan_width); + /* Minimum Fc should be 2 : ensure we will connect to a pair of routing tracks */ + actual_Fc = std::max(2, actual_Fc); + /* Compute the step between two connection from this IPIN to tracks: + * step = W' / Fc', W' and Fc' are the adapted W and Fc from actual_track_list and Fc_in + */ + size_t track_step = actual_track_list.size() / actual_Fc; + /* Track step mush be a multiple of 2!!!*/ + if (0 != track_step % 2) { + track_step--; /* minus 1 to increase connectivity */ + } + /* Make sure step should be at least 2 */ + track_step = std::max(2, (int)track_step); + /* Adapt offset to the range of actual_track_list */ + size_t actual_offset = offset % actual_track_list.size(); + /* rotate the track list by an offset */ + std::rotate(actual_track_list.begin(), actual_track_list.begin() + actual_offset, actual_track_list.end()); + + /* Assign tracks: since we assign 2 track per round, we increment itrack by 2* step */ + for (size_t itrack = 0; itrack < actual_track_list.size(); itrack = itrack + 2 * track_step) { + /* Update pin2track map */ + size_t ipin_side_index = ipin_side_manager.to_size_t(); + size_t track_index = actual_track_list[itrack]; + size_t ipin_index = ipin_node - rr_graph->rr_node; + (*track2ipin_map)[ipin_side_index][track_index].push_back(ipin_index); + (*track2ipin_map)[ipin_side_index][track_index + 1].push_back(ipin_index); + } + } + + return; +} + +/************************************************************************ + * Build opin2track_map for an OPIN + * 1. build a list of routing tracks which are allowed for connections + * We will check the Switch Block (SB) population of each routing track. + * By comparing current chan_y - ylow, we can determine if a SB connection + * is required for each routing track + * 2. Divide the routing tracks by segment types, so that we can balance + * the connections between OPINs and different types of routing tracks. + * 3. Scale the Fc of each pin to the actual number of routing tracks + * actual_Fc = (int) Fc * num_tracks / chan_width + ***********************************************************************/ +static +void build_gsb_one_opin_pin2track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_side opin_side, + const size_t opin_node_id, + const size_t Fc, + const size_t offset, + const std::vector segment_inf, + t_pin2track_map* opin2track_map) { + /* Get a list of segment_ids*/ + std::vector seg_list = rr_gsb.get_chan_segment_ids(opin_side); + enum e_side chan_side = opin_side; + size_t chan_width = rr_gsb.get_chan_width(chan_side); + Side opin_side_manager(opin_side); + + for (size_t iseg = 0; iseg < seg_list.size(); ++iseg) { + /* Get a list of node that have the segment id */ + std::vector track_list = rr_gsb.get_chan_node_ids_by_segment_ids(chan_side, seg_list[iseg]); + /* Refine the track_list: keep those will have connection blocks in the GSB */ + std::vector actual_track_list; + for (size_t inode = 0; inode < track_list.size(); ++inode) { + /* Check if tracks allow connection blocks in the GSB*/ + if ( (false == is_gsb_in_track_sb_population(rr_gsb, chan_side, track_list[inode], segment_inf)) + && (TRACK_START != determine_track_status_of_gsb(rr_gsb, chan_side, track_list[inode])) ) { + continue; /* Bypass condition */ + } + /* Push the node to actual_track_list */ + actual_track_list.push_back(track_list[inode]); + } + + /* Scale Fc */ + int actual_Fc = Fc * (float)(actual_track_list.size() / chan_width); + /* Minimum Fc should be 1 : ensure we will drive 1 routing track */ + actual_Fc = std::max(1, actual_Fc); + /* Compute the step between two connection from this IPIN to tracks: + * step = W' / Fc', W' and Fc' are the adapted W and Fc from actual_track_list and Fc_in + */ + size_t track_step = actual_track_list.size() / actual_Fc; + /* Track step mush be a multiple of 2!!!*/ + /* Make sure step should be at least 1 */ + track_step = std::max(1, (int)track_step); + /* Adapt offset to the range of actual_track_list */ + size_t actual_offset = offset % actual_track_list.size(); + /* rotate the track list by an offset */ + std::rotate(actual_track_list.begin(), actual_track_list.begin() + actual_offset, actual_track_list.end()); + + /* Assign tracks */ + for (size_t itrack = 0; itrack < actual_track_list.size(); itrack = itrack + track_step) { + /* Update pin2track map */ + size_t opin_side_index = opin_side_manager.to_size_t(); + size_t track_index = actual_track_list[itrack]; + size_t track_rr_node_index = rr_gsb.get_chan_node(chan_side, track_index) - rr_graph->rr_node; + (*opin2track_map)[opin_side_index][opin_node_id].push_back(track_rr_node_index); + } + } + + return; +} + + +/************************************************************************ + * Build the track_to_ipin_map[gsb_side][0..chan_width-1][ipin_indices] + * based on the existing routing resources in the General Switch Block (GSB) + * This function supports both X-directional and Y-directional tracks + * The mapping is done in the following steps: + * 1. Build ipin_to_track_map[gsb_side][0..num_ipin_nodes-1][track_indices] + * For each IPIN, we ensure at least one connection to the tracks. + * Then, we assign IPINs to tracks evenly while satisfying the actual_Fc + * 2. Convert the ipin_to_track_map to track_to_ipin_map + ***********************************************************************/ +t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const std::vector segment_inf, + const int* Fc_in) { + t_track2pin_map track2ipin_map; + /* Resize the matrix */ + track2ipin_map.resize(rr_gsb.get_num_sides()); + + /* offset counter: it aims to balance the track-to-IPIN for each connection block */ + std::vector offset; + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side ipin_side = side_manager.get_side(); + /* Get the chan_side */ + enum e_side chan_side = rr_gsb.get_cb_chan_side(ipin_side); + Side chan_side_manager(chan_side); + offset.resize(chan_side_manager.to_size_t()); + } + /* Initial offset */ + offset.assign(offset.size(), 0); + + /* Walk through each side */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side ipin_side = side_manager.get_side(); + /* Get the chan_side */ + enum e_side chan_side = rr_gsb.get_cb_chan_side(ipin_side); + Side chan_side_manager(chan_side); + /* This track2pin mapping is for Connection Blocks, so we only care two sides! */ + /* Get channel width and resize the matrix */ + size_t chan_width = rr_gsb.get_chan_width(chan_side); + track2ipin_map[side].resize(chan_width); + /* Find the ipin/opin nodes */ + for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(ipin_side); ++inode) { + t_rr_node* ipin_node = rr_gsb.get_ipin_node(ipin_side, inode); + /* Get Fc of the ipin */ + int ipin_Fc = Fc_in[ipin_node->ptc_num]; + /* skip Fc = 0 */ + if (0 == ipin_Fc) { + continue; + } + /* Build track2ipin_map for this IPIN */ + build_gsb_one_ipin_track2pin_map(rr_graph, rr_gsb, ipin_side, inode, ipin_Fc, + /* Give an offset for the first track that this ipin will connect to */ + offset[chan_side_manager.to_size_t()], + segment_inf, &track2ipin_map); + /* update offset */ + offset[chan_side_manager.to_size_t()] += 2; + } + } + + return track2ipin_map; +} + +/************************************************************************ + * Build the opin_to_track_map[gsb_side][0..num_opin_nodes-1][track_indices] + * based on the existing routing resources in the General Switch Block (GSB) + * This function supports both X-directional and Y-directional tracks + * The mapping is done in the following steps: + * 1. Build a list of routing tracks whose starting points locate at this GSB + * (xlow - gsb_x == 0) + * 2. Divide the routing tracks by segment types, so that we can balance + * the connections between OPINs and different types of routing tracks. + * 3. Scale the Fc of each pin to the actual number of routing tracks + * actual_Fc = (int) Fc * num_tracks / chan_width + ***********************************************************************/ +t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const std::vector segment_inf, + const int* Fc_out) { + t_pin2track_map opin2track_map; + /* Resize the matrix */ + opin2track_map.resize(rr_gsb.get_num_sides()); + + /* offset counter: it aims to balance the OPIN-to-track for each switch block */ + std::vector offset; + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + /* Get the chan_side: which is the same as the opin side */ + Side side_manager(side); + offset.resize(side_manager.to_size_t()); + } + /* Initial offset */ + offset.assign(offset.size(), 0); + + /* Walk through each side */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side opin_side = side_manager.get_side(); + /* Get the chan_side */ + /* This track2pin mapping is for Connection Blocks, so we only care two sides! */ + /* Get channel width and resize the matrix */ + size_t num_opin_nodes = rr_gsb.get_num_opin_nodes(opin_side); + opin2track_map[side].resize(num_opin_nodes); + /* Find the ipin/opin nodes */ + for (size_t inode = 0; inode < num_opin_nodes; ++inode) { + t_rr_node* opin_node = rr_gsb.get_opin_node(opin_side, inode); + /* Get Fc of the ipin */ + int opin_Fc = Fc_out[opin_node->ptc_num]; + /* skip Fc = 0 */ + if (0 == opin_Fc) { + continue; + } + /* Build track2ipin_map for this IPIN */ + build_gsb_one_opin_pin2track_map(rr_graph, rr_gsb, opin_side, inode, opin_Fc, + /* Give an offset for the first track that this ipin will connect to */ + offset[side_manager.to_size_t()], + segment_inf, &opin2track_map); + /* update offset */ + offset[side_manager.to_size_t()] += 2; + } + } + + return opin2track_map; +} + + +/************************************************************************ + * Add all direct clb-pin-to-clb-pin edges to given opin + ***********************************************************************/ +void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, + const DeviceCoordinator& device_size, + const std::vector> grids, + const DeviceCoordinator& from_grid_coordinator, + const t_grid_tile& from_grid, + const int delayless_switch, + const int num_directs, + const t_direct_inf *directs, + const t_clb_to_clb_directs *clb_to_clb_directs) { + t_type_ptr grid_type = from_grid.type; + + /* Iterate through all direct connections */ + for (int i = 0; i < num_directs; ++i) { + /* Bypass unmatched direct clb-to-clb connections */ + if (grid_type != clb_to_clb_directs[i].from_clb_type) { + continue; + } + bool swap; + int max_index, min_index; + /* Compute index of opin with regards to given pins */ + if ( clb_to_clb_directs[i].from_clb_pin_start_index + > clb_to_clb_directs[i].from_clb_pin_end_index) { + swap = true; + max_index = clb_to_clb_directs[i].from_clb_pin_start_index; + min_index = clb_to_clb_directs[i].from_clb_pin_end_index; + } else { + swap = false; + min_index = clb_to_clb_directs[i].from_clb_pin_start_index; + max_index = clb_to_clb_directs[i].from_clb_pin_end_index; + } + /* get every opin in the range */ + for (int opin = min_index; opin <= max_index; ++opin) { + int offset = opin - min_index; + /* This opin is specified to connect directly to an ipin, now compute which ipin to connect to */ + DeviceCoordinator to_grid_coordinator(from_grid_coordinator.get_x() + directs[i].x_offset, + from_grid_coordinator.get_y() + directs[i].y_offset); + if ( (to_grid_coordinator.get_x() < device_size.get_x() - 1) + && (to_grid_coordinator.get_y() < device_size.get_y() - 1) ) { + int ipin = OPEN; + if ( clb_to_clb_directs[i].to_clb_pin_start_index + > clb_to_clb_directs[i].to_clb_pin_end_index) { + if (true == swap) { + ipin = clb_to_clb_directs[i].to_clb_pin_end_index + offset; + } else { + ipin = clb_to_clb_directs[i].to_clb_pin_start_index - offset; + } + } else { + if(true == swap) { + ipin = clb_to_clb_directs[i].to_clb_pin_end_index - offset; + } else { + ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset; + } + } + /* Get the pin index in the rr_graph */ + int from_grid_ofs = from_grid.offset; + int to_grid_ofs = grids[to_grid_coordinator.get_x()][to_grid_coordinator.get_y()].offset; + int opin_node_id = get_rr_node_index(from_grid_coordinator.get_x(), + from_grid_coordinator.get_y() - from_grid_ofs, + OPIN, opin, rr_graph->rr_node_indices); + int ipin_node_id = get_rr_node_index(to_grid_coordinator.get_x(), + to_grid_coordinator.get_y() - to_grid_ofs, + IPIN, ipin, rr_graph->rr_node_indices); + /* add edges to the opin_node */ + add_one_edge_for_two_rr_nodes(rr_graph, opin_node_id, ipin_node_id, + delayless_switch); + } + } + } + + return; +} + +/************************************************************************ + * End of file : rr_graph_tileable_gsb.cpp + ***********************************************************************/ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h new file mode 100755 index 000000000..8097139b3 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h @@ -0,0 +1,62 @@ +#ifndef RR_GRAPH_TILEABLE_GSB_H +#define RR_GRAPH_TILEABLE_GSB_H + +#include + +#include "vtr_ndmatrix.h" + +#include "rr_blocks.h" +#include "fpga_x2p_types.h" + + +/************************************************************************ + * Data stuctures related to the functions + ***********************************************************************/ +typedef std::vector>> t_track2track_map; +typedef std::vector>> t_track2pin_map; +typedef std::vector>> t_pin2track_map; + +/************************************************************************ + * Functions + ***********************************************************************/ +t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_switch_block_type sb_type, + const int Fs, + const std::vector segment_inf); + +RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, + const std::vector device_chan_width, + const std::vector segment_inf, + const DeviceCoordinator& gsb_coordinator, + t_rr_graph* rr_graph); + +void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, const RRGSB* rr_gsb, + const t_track2pin_map track2ipin_map, + const t_pin2track_map opin2track_map, + const t_track2track_map track2track_map); + +t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const std::vector segment_inf, + const int* Fc_in); + +t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const std::vector segment_inf, + const int* Fc_out); + +void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, + const DeviceCoordinator& device_size, + const std::vector> grids, + const DeviceCoordinator& from_grid_coordinator, + const t_grid_tile& from_grid, + const int delayless_switch, + const int num_directs, + const t_direct_inf *directs, + const t_clb_to_clb_directs *clb_to_clb_directs); + + + +#endif + diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp deleted file mode 100755 index df894c81a..000000000 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp +++ /dev/null @@ -1,461 +0,0 @@ -/********************************************************** - * MIT License - * - * Copyright (c) 2018 LNIS - The University of Utah - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ***********************************************************************/ - -/************************************************************************ - * Filename: rr_graph_tileable_sbox.cpp - * Created by: Xifan Tang - * Change history: - * +-------------------------------------+ - * | Date | Author | Notes - * +-------------------------------------+ - * | 2019/06/19 | Xifan Tang | Created - * +-------------------------------------+ - ***********************************************************************/ -/************************************************************************ - * This file contains a builder for track-to-track connections inside a - * tileable General Switch Block (GSB). - ***********************************************************************/ - -#include -#include - -#include - -#include "vpr_types.h" -#include "rr_graph_tileable_sbox.h" - -/************************************************************************ - * Internal data structures - ***********************************************************************/ -typedef std::vector> t_track_group; - -/************************************************************************ - * A enumeration to list the status of a track inside a GSB - * 1. start; 2. end; 3. passing - * This is used to group tracks which ease the building of - * track-to-track mapping matrix - ***********************************************************************/ -enum e_track_status { - TRACK_START, - TRACK_END, - TRACK_PASS, - NUM_TRACK_STATUS /* just a place holder to get the number of status */ -}; - -/************************************************************************ - * Check if a track starts from this GSB or not - * (xlow, ylow) should be same as the GSB side coordinator - * - * Check if a track ends at this GSB or not - * (xhigh, yhigh) should be same as the GSB side coordinator - ***********************************************************************/ -static -enum e_track_status determine_track_status_of_gsb(const RRGSB& rr_gsb, - const enum e_side gsb_side, - const size_t track_id) { - enum e_track_status track_status = TRACK_PASS; - /* Get the rr_node */ - t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); - /* Get the coordinators */ - DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); - - /* INC_DIRECTION start_track: (xlow, ylow) should be same as the GSB side coordinator */ - if ( ((size_t)track_node->xlow == side_coordinator.get_x()) - && ((size_t)track_node->ylow == side_coordinator.get_y()) - && (OUT_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { - /* Double check: start track should be an OUTPUT PORT of the GSB */ - track_status = TRACK_START; - } - /* INC_DIRECTION end_track: (xhigh, yhigh) should be same as the GSB side coordinator */ - if ( ((size_t)track_node->xhigh == side_coordinator.get_x()) - && ((size_t)track_node->yhigh == side_coordinator.get_y()) - && (IN_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { - /* Double check: end track should be an INPUT PORT of the GSB */ - track_status = TRACK_END; - } - - return track_status; -} - -/************************************************************************ - * Check if the GSB is in the Switch Block (SB) population list of the segment - * SB population of a L3 wire: 1 0 0 1 - * - * +----+ +----+ +----+ +----+ - * | SB |--->| SB |--->| SB |--->| SB | - * +----+ +----+ +----+ +----+ - * Engage SB connection Yes No No Yes - * - * We will find the offset between gsb_side_coordinator and (xlow,ylow) of the track - * Use the offset to check if the tracks should engage in this GSB connection - ***********************************************************************/ -static -bool is_gsb_in_track_sb_population(const RRGSB& rr_gsb, - const enum e_side gsb_side, - const int track_id, - const std::vector segment_inf) { - /* Get the rr_node */ - t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); - /* Get the coordinators */ - DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); - - /* Get the offset */ - size_t offset = (side_coordinator.get_x() - track_node->xlow) - + (side_coordinator.get_y() - track_node->ylow); - - /* Get segment id */ - size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); - /* validate offset */ - assert (offset < (size_t)segment_inf[seg_id].sb_len); - - /* Get the SB population */ - bool in_sb_population = false; - if (TRUE == segment_inf[seg_id].sb[offset]) { - in_sb_population = true; - } - return in_sb_population; -} - -/************************************************************************ - * Create a list of track_id based on the to_track and num_to_tracks - * We consider the following list [to_track, to_track + Fs/3 - 1] - * if the [to_track + Fs/3 - 1] exceeds the num_to_tracks, we start over from 0! -***********************************************************************/ -static -std::vector get_to_track_list(const int Fs, const int to_track, const int num_to_tracks) { - std::vector to_tracks; - for (int i = 0; i < Fs; i = i + 3) { - /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied - * The optimal track selection should be done in a more scientific way!!! - */ - size_t to_track_i = to_track + i; - /* make sure the track id is still in range */ - if ( to_track_i > (size_t)num_to_tracks) { - to_track_i = to_track_i % num_to_tracks; - } - /* from track must be connected */ - to_tracks.push_back(to_track_i); - } - return to_tracks; -} - -/************************************************************************ - * This function aims to return the track indices that drive the from_track - * in a Switch Block - * The track_ids to return will depend on different topologies of SB - * SUBSET, UNIVERSAL, and WILTON. - ***********************************************************************/ -static -std::vector get_switch_block_to_track_id(const enum e_switch_block_type switch_block_type, - const int Fs, - const enum e_side from_side, - const int from_track, - const enum e_side to_side, - const int num_to_tracks) { - - /* This routine returns the track number to which the from_track should - * connect. It supports any Fs % 3 == 0, switch blocks. - */ - std::vector to_tracks; - - /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied - * The optimal track selection should be done in a more scientific way!!! - */ - - assert (0 == Fs % 3); - - switch (switch_block_type) { - case SUBSET: /* NB: Global routing uses SUBSET too */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - /* Finish, we return */ - return to_tracks; - case UNIVERSAL: - if ( (from_side == LEFT) - || (from_side == RIGHT) ) { - /* For the prev_side, to_track is from_track - * For the next_side, to_track is num_to_tracks - 1 - from_track - * For the opposite_side, to_track is always from_track - */ - Side side_manager(from_side); - if ( (to_side == side_manager.get_opposite()) - || (to_side == side_manager.get_rotate_counterclockwise()) ) { - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == side_manager.get_rotate_clockwise()) { - to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); - } - } - - if ( (from_side == TOP) - || (from_side == BOTTOM) ) { - /* For the next_side, to_track is from_track - * For the prev_side, to_track is num_to_tracks - 1 - from_track - * For the opposite_side, to_track is always from_track - */ - Side side_manager(from_side); - if ( (to_side == side_manager.get_opposite()) - || (to_side == side_manager.get_rotate_clockwise()) ) { - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == side_manager.get_rotate_counterclockwise()) { - to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); - } - } - /* Finish, we return */ - return to_tracks; - /* End switch_block_type == UNIVERSAL case. */ - case WILTON: - /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ - if (from_side == LEFT) { - if (to_side == RIGHT) { /* CHANX to CHANX */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); - } else if (to_side == BOTTOM) { - to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); - } - } else if (from_side == RIGHT) { - if (to_side == LEFT) { /* CHANX to CHANX */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); - } else if (to_side == BOTTOM) { - to_tracks = get_to_track_list(Fs, (num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); - } - } else if (from_side == BOTTOM) { - if (to_side == TOP) { /* CHANY to CHANY */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); - } else if (to_side == RIGHT) { - to_tracks = get_to_track_list(Fs, (2 * num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); - } - } else if (from_side == TOP) { - if (to_side == BOTTOM) { /* CHANY to CHANY */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); - } else if (to_side == RIGHT) { - to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); - } - } - /* Finish, we return */ - return to_tracks; - /* End switch_block_type == WILTON case. */ - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d]) Invalid switch block pattern !\n", - __FILE__, __LINE__); - exit(1); - } - - return to_tracks; -} - - -/************************************************************************ - * Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices] - * For a group of from_track nodes and to_track nodes - * For each side of from_tracks, we call a routine to get the list of to_tracks - * Then, we fill the track2track_map - ***********************************************************************/ -static -void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, - const RRGSB& rr_gsb, - const enum e_switch_block_type sb_type, - const int Fs, - const t_track_group from_tracks, /* [0..gsb_side][track_indices] */ - const t_track_group to_tracks, /* [0..gsb_side][track_indices] */ - t_track2track_map* track2track_map) { - for (size_t side = 0; side < from_tracks.size(); ++side) { - Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); - /* Find the other sides where the start tracks will locate */ - std::vector to_track_sides; - /* 0. opposite side */ - to_track_sides.push_back(side_manager.get_opposite()); - /* 1. prev side */ - /* Previous side definition: TOP => LEFT; RIGHT=>TOP; BOTTOM=>RIGHT; LEFT=>BOTTOM */ - to_track_sides.push_back(side_manager.get_rotate_counterclockwise()); - /* 2. next side */ - /* Next side definition: TOP => RIGHT; RIGHT=>BOTTOM; BOTTOM=>LEFT; LEFT=>TOP */ - to_track_sides.push_back(side_manager.get_rotate_clockwise()); - - for (size_t inode = 0; inode < from_tracks[side].size(); ++inode) { - for (size_t to_side_id = 0; to_side_id < to_track_sides.size(); ++to_side_id) { - enum e_side to_side = to_track_sides[to_side_id]; - Side to_side_manager(to_side); - size_t to_side_index = to_side_manager.to_size_t(); - /* Bypass those to_sides have no nodes */ - if (0 == to_tracks[to_side_index].size()) { - continue; - } - /* Get other track_ids depending on the switch block pattern */ - /* Find the track ids that will start at the other sides */ - std::vector to_track_ids = get_switch_block_to_track_id(sb_type, Fs, gsb_side, inode, - to_side, - to_tracks[to_side_index].size()); - /* Update the track2track_map: */ - for (size_t to_track_id = 0; to_track_id < to_track_ids.size(); ++to_track_id) { - size_t from_side_index = side_manager.to_size_t(); - size_t from_track_index = from_tracks[side][inode]; - size_t to_track_index = to_tracks[to_side_index][to_track_ids[to_track_id]]; - t_rr_node* to_track_node = rr_gsb.get_chan_node(to_side, to_track_index); - (*track2track_map)[from_side_index][from_track_index].push_back(to_track_node - rr_graph->rr_node); - } - } - } - } - - return; -} - -/************************************************************************ - * Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices] - * based on the existing routing resources in the General Switch Block (GSB) - * The track_indices is the indices of tracks that the node at from_side and [0..chan_width-1] will drive - * IMPORTANT: the track_indices are the indicies in the GSB context, but not the rr_graph!!! - * We separate the connections into two groups: - * Group 1: the routing tracks start from this GSB - * We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON) - * Group 2: the routing tracks do not start from this GSB (bypassing wires) - * We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON) - * but we will check the Switch Block (SB) population of these - * routing segments, and determine which requires connections - * - * CHANY CHANY CHANY CHANY - * [0] [1] [2] [3] - * start yes no yes no - * end +-------------------------+ start Group 1 Group 2 - * no CHANX[0] | TOP | CHANX[0] yes TOP/BOTTOM TOP/BOTTOM - * | | CHANY[0,2] CHANY[1,3] - * yes CHANX[1] | | CHANX[1] no - * | LEFT RIGHT | - * no CHANX[2] | | CHANX[2] yes - * | | - * yes CHANX[3] | BOTTOM | CHANX[3] no - * +-------------------------+ - * CHANY CHANY CHANY CHANY - * [0] [1] [2] [3] - * start yes no yes no - * - * The mapping is done in the following steps: (For each side of the GSB) - * 1. Build a list of tracks that will start from this side - * if a track starts, its xlow/ylow is the same as the x,y of this gsb - * 2. Build a list of tracks on the other sides belonging to Group 1. - * Take the example of RIGHT side, we will collect - * a. tracks that will end at the LEFT side - * b. tracks that will start at the TOP side - * c. tracks that will start at the BOTTOM side - * 3. Apply switch block patterns to Group 1 (SUBSET, UNIVERSAL, WILTON) - * 4. Build a list of tracks on the other sides belonging to Group 1. - * Take the example of RIGHT side, we will collect - * a. tracks that will bypass at the TOP side - * b. tracks that will bypass at the BOTTOM side - * 5. Apply switch block patterns to Group 2 (SUBSET, UNIVERSAL, WILTON) - ***********************************************************************/ -t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, - const RRGSB& rr_gsb, - const enum e_switch_block_type sb_type, - const int Fs, - const std::vector segment_inf) { - t_track2track_map track2track_map; /* [0..gsb_side][0..chan_width][track_indices] */ - - /* Categorize tracks into 3 groups: - * (1) tracks will start here - * (2) tracks will end here - * (2) tracks will just pass through the SB */ - t_track_group start_tracks; /* [0..gsb_side][track_indices] */ - t_track_group end_tracks; /* [0..gsb_side][track_indices] */ - t_track_group pass_tracks; /* [0..gsb_side][track_indices] */ - - /* resize to the number of sides */ - start_tracks.resize(rr_gsb.get_num_sides()); - end_tracks.resize(rr_gsb.get_num_sides()); - pass_tracks.resize(rr_gsb.get_num_sides()); - - /* Walk through each side */ - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); - /* Build a list of tracks that will start from this side */ - for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { - /* check if this track will start from here */ - enum e_track_status track_status = determine_track_status_of_gsb(rr_gsb, gsb_side, inode); - switch (track_status) { - case TRACK_START: - /* update starting track list */ - start_tracks[gsb_side].push_back(inode); - break; - case TRACK_END: - /* Update end track list */ - end_tracks[gsb_side].push_back(inode); - break; - case TRACK_PASS: - /* We need to check Switch block population of this track - * The track node will not be considered if there supposed to be no SB at this position - */ - if (true == is_gsb_in_track_sb_population(rr_gsb, gsb_side, inode, segment_inf)) { - /* Update passing track list */ - pass_tracks[gsb_side].push_back(inode); - } - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d]) Invalid track status!\n", - __FILE__, __LINE__); - exit(1); - } - } - } - - /* Allocate track2track map */ - track2track_map.resize(rr_gsb.get_num_sides()); - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); - /* allocate track2track_map[gsb_side] */ - track2track_map[side].resize(rr_gsb.get_chan_width(gsb_side)); - for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { - /* allocate track2track_map[gsb_side][inode] */ - track2track_map[side][inode].clear(); - } - } - - /* For Group 1: we build connections between end_tracks and start_tracks*/ - build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb, - sb_type, Fs, - end_tracks, start_tracks, - &track2track_map); - - /* For Group 2: we build connections between end_tracks and start_tracks*/ - /* Currently, I use the same Switch Block pattern for the passing tracks and end tracks, - * TODO: This can be improved with different patterns! - */ - build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb, - sb_type, Fs, - pass_tracks, start_tracks, - &track2track_map); - - return track2track_map; -} - diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h deleted file mode 100755 index 3079cbea8..000000000 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef RR_GRAPH_TILEABLE_SBOX_H -#define RR_GRAPH_TILEABLE_SBOX_H - -#include - -#include "vtr_ndmatrix.h" - -#include "rr_blocks.h" -#include "fpga_x2p_types.h" - -typedef std::vector>> t_track2track_map; - -t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, - const RRGSB& rr_gsb, - const enum e_switch_block_type sb_type, - const int Fs, - const std::vector segment_inf); - -#endif - diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp index cb8de00d3..d150b53a6 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp @@ -125,6 +125,24 @@ std::vector RRChan::get_segment_ids() const { return seg_list; } +/* Get a list of nodes whose segment_id is specified */ +std::vector RRChan::get_node_ids_by_segment_ids(size_t seg_id) const { + std::vector node_list; + + /* make sure a clean start */ + node_list.clear(); + + /* Traverse node_segments */ + for (size_t inode = 0; inode < get_chan_width(); ++inode) { + /* Try to find the node_segment id in the list */ + if ( seg_id == node_segments_[inode] ) { + node_list.push_back(inode); + } + } + + return node_list; +} + /* Mutators */ void RRChan::set(const RRChan& rr_chan) { /* Ensure a clean start */ @@ -611,6 +629,22 @@ RRChan RRGSB::get_chan(enum e_side side) const { return chan_node_[side_manager.to_size_t()]; } +/* Get a list of segments used in this routing channel */ +std::vector RRGSB::get_chan_segment_ids(enum e_side side) const { + Side side_manager(side); + assert(side_manager.validate()); + + /* Ensure the side is valid in the context of this switch block */ + assert( validate_side(side) ); + + return get_chan(side).get_segment_ids(); +} + +/* Get a list of rr_nodes whose sed_id is specified */ +std::vector RRGSB::get_chan_node_ids_by_segment_ids(enum e_side side, size_t seg_id) const { + return get_chan(side).get_node_ids_by_segment_ids(seg_id); +} + /* get a rr_node at a given side and track_id */ t_rr_node* RRGSB::get_chan_node(enum e_side side, size_t track_id) const { Side side_manager(side); @@ -1302,6 +1336,24 @@ enum e_side RRGSB::get_cb_chan_side(t_rr_type cb_type) const { } } +/* Get the side of routing channel in the GSB according to the side of IPIN */ +enum e_side RRGSB::get_cb_chan_side(enum e_side ipin_side) const { + switch(ipin_side) { + case TOP: + return LEFT; + case RIGHT: + return TOP; + case BOTTOM: + return LEFT; + case LEFT: + return TOP; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid type of ipin_side!\n", + __FILE__, __LINE__); + exit(1); + } +} DeviceCoordinator RRGSB::get_side_block_coordinator(enum e_side side) const { Side side_manager(side); @@ -1337,6 +1389,13 @@ DeviceCoordinator RRGSB::get_side_block_coordinator(enum e_side side) const { return ret; } +DeviceCoordinator RRGSB::get_grid_coordinator() const { + DeviceCoordinator ret(get_sb_x(), get_sb_y()); + ret.set_y(ret.get_y() + 1); + + return ret; +} + /* Public Accessors Verilog writer */ const char* RRGSB::gen_cb_verilog_routing_track_name(t_rr_type cb_type, size_t track_id) const { diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h index 475be8ab4..a1cd95856 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h @@ -84,6 +84,7 @@ class RRChan { int get_node_segment(size_t track_num) const; bool is_mirror(const RRChan& cand) const; /* evaluate if two RR_chan is mirror to each other */ std::vector get_segment_ids() const; /* Get a list of segments used in this routing channel */ + std::vector get_node_ids_by_segment_ids(size_t seg_id) const; /* Get a list of segments used in this routing channel */ public: /* Mutators */ void set(const RRChan&); /* copy */ void set_type(t_rr_type type); /* modify type */ @@ -188,6 +189,8 @@ class RRGSB { size_t get_max_chan_width() const; /* Get the maximum number of routing tracks on all sides */ enum PORTS get_chan_node_direction(enum e_side side, size_t track_id) const; /* Get the direction of a rr_node at a given side and track_id */ RRChan get_chan(enum e_side side) const; /* get a rr_node at a given side and track_id */ + std::vector get_chan_segment_ids(enum e_side side) const; /* Get a list of segments used in this routing channel */ + std::vector get_chan_node_ids_by_segment_ids(enum e_side side, size_t seg_id) const; /* Get a list of segments used in this routing channel */ t_rr_node* get_chan_node(enum e_side side, size_t track_id) const; /* get a rr_node at a given side and track_id */ size_t get_chan_node_segment(enum e_side side, size_t track_id) const; /* get the segment id of a channel rr_node */ size_t get_num_ipin_nodes(enum e_side side) const; /* Get the number of IPIN rr_nodes on a side */ @@ -232,7 +235,9 @@ class RRGSB { size_t get_cb_y(t_rr_type cb_type) const; /* get the y coordinator of this X/Y-direction block */ DeviceCoordinator get_cb_coordinator(t_rr_type cb_type) const; /* Get the coordinator of the X/Y-direction CB */ enum e_side get_cb_chan_side(t_rr_type cb_type) const; /* get the side of a Connection block */ + enum e_side get_cb_chan_side(enum e_side ipin_side) const; /* get the side of a Connection block */ DeviceCoordinator get_side_block_coordinator(enum e_side side) const; + DeviceCoordinator get_grid_coordinator() const; public: /* Verilog writer */ const char* gen_sb_verilog_module_name() const; const char* gen_sb_verilog_instance_name() const; diff --git a/vpr7_x2p/vpr/SRC/route/check_rr_graph.c b/vpr7_x2p/vpr/SRC/route/check_rr_graph.c index 770dc130a..17fc4b34e 100755 --- a/vpr7_x2p/vpr/SRC/route/check_rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/check_rr_graph.c @@ -23,15 +23,12 @@ static void check_pass_transistors(int from_node); /************************ Subroutine definitions ****************************/ -void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types, - INP int L_nx, INP int L_ny, INP int nodes_per_chan, INP int Fs, - INP int num_seg_types, INP int num_switches, - INP t_segment_inf * segment_inf, INP int global_route_switch, - INP int delayless_switch, INP int wire_to_ipin_switch, - t_seg_details * seg_details, int **Fc_in, int **Fc_out, - int *****opin_to_track_map, int *****ipin_to_track_map, - t_ivec **** track_to_ipin_lookup, t_ivec *** switch_block_conn, - boolean * perturb_ipins) { +void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, + INP const int L_nx, INP const int L_ny, INP const int nodes_per_chan, INP int Fs, + INP const int num_seg_types, INP const int num_switches, + INP const t_segment_inf * segment_inf, INP const int global_route_switch, + INP const int delayless_switch, INP const int wire_to_ipin_switch, + int **Fc_in, int **Fc_out) { int *num_edges_from_current_to_node; /* [0..num_rr_nodes-1] */ int *total_edges_to_node; /* [0..num_rr_nodes-1] */ diff --git a/vpr7_x2p/vpr/SRC/route/check_rr_graph.h b/vpr7_x2p/vpr/SRC/route/check_rr_graph.h index 2dd21a124..0d2d06bdf 100755 --- a/vpr7_x2p/vpr/SRC/route/check_rr_graph.h +++ b/vpr7_x2p/vpr/SRC/route/check_rr_graph.h @@ -1,26 +1,20 @@ #ifndef CHECK_RR_GRAPH_H #define CHECK_RR_GRAPH_H -void check_rr_graph(INP t_graph_type graph_type, +void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, - INP int L_nx, - INP int L_ny, - INP int nodes_per_chan, - INP int Fs, - INP int num_seg_types, - INP int num_switches, - INP t_segment_inf * segment_inf, - INP int global_route_switch, - INP int delayless_switch, - INP int wire_to_ipin_switch, - t_seg_details * seg_details, + INP const int L_nx, + INP const int L_ny, + INP const int nodes_per_chan, + INP const int Fs, + INP const int num_seg_types, + INP const int num_switches, + INP const t_segment_inf * segment_inf, + INP const int global_route_switch, + INP const int delayless_switch, + INP const int wire_to_ipin_switch, int ** Fc_in, - int ** Fc_out, - int *****opin_to_track_map, - int *****ipin_to_track_map, - t_ivec **** track_to_ipin_lookup, - t_ivec *** switch_block_conn, - boolean * perturb_ipins); + int ** Fc_out); void check_node(int inode, enum e_route_type route_type); diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.c b/vpr7_x2p/vpr/SRC/route/rr_graph.c index 51c4a5035..b111fc149 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.c @@ -458,9 +458,7 @@ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types, check_rr_graph(graph_type, types, L_nx, L_ny, nodes_per_chan, Fs, num_seg_types, num_switches, segment_inf, global_route_switch, - delayless_switch, wire_to_ipin_switch, seg_details, Fc_in, Fc_out, - opin_to_track_map, ipin_to_track_map, track_to_ipin_lookup, - switch_block_conn, perturb_ipins); + delayless_switch, wire_to_ipin_switch, Fc_in, Fc_out); /* Free all temp structs */ if (seg_details) { @@ -514,9 +512,9 @@ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types, } } -void rr_graph_externals(t_timing_inf timing_inf, - t_segment_inf * segment_inf, int num_seg_types, int nodes_per_chan, - int wire_to_ipin_switch, enum e_base_cost_type base_cost_type) { +void rr_graph_externals(const t_timing_inf timing_inf, + const t_segment_inf * segment_inf, const int num_seg_types, const int nodes_per_chan, + const int wire_to_ipin_switch, const enum e_base_cost_type base_cost_type) { add_rr_graph_C_from_switches(timing_inf.C_ipin_cblock); alloc_and_load_rr_indexed_data(segment_inf, num_seg_types, rr_node_indices, nodes_per_chan, wire_to_ipin_switch, base_cost_type); diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.h b/vpr7_x2p/vpr/SRC/route/rr_graph.h index c8cb18aa3..9e23b0187 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.h +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.h @@ -59,9 +59,9 @@ alloc_and_load_actual_fc(INP int L_num_types, INP t_type_ptr types, INP int nodes_per_chan, INP boolean is_Fc_out, INP enum e_directionality directionality, OUTP boolean * Fc_clipped, INP boolean ignore_Fc_0); -void rr_graph_externals(t_timing_inf timing_inf, - t_segment_inf * segment_inf, int num_seg_types, int nodes_per_chan, - int wire_to_ipin_switch, enum e_base_cost_type base_cost_type); +void rr_graph_externals(const t_timing_inf timing_inf, + const t_segment_inf * segment_inf, const int num_seg_types, const int nodes_per_chan, + const int wire_to_ipin_switch, const enum e_base_cost_type base_cost_type); /* Xifan Tang: Functions shared by tileable rr_graph generator */ diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.c b/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.c index 9a4f6e7a8..476d093b9 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.c +++ b/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.c @@ -25,7 +25,7 @@ static float get_average_opin_delay(t_ivec *** L_rr_node_indices, static void load_rr_indexed_data_T_values(int index_start, int num_indices_to_load, t_rr_type rr_type, int nodes_per_chan, - t_ivec *** L_rr_node_indices, t_segment_inf * segment_inf); + t_ivec *** L_rr_node_indices, const t_segment_inf * segment_inf); /******************** Subroutine definitions *********************************/ @@ -42,7 +42,7 @@ static void load_rr_indexed_data_T_values(int index_start, * etc. more expensive than others. I give each segment type in an * * x-channel its own cost_index, and each segment type in a y-channel its * * own cost_index. */ -void alloc_and_load_rr_indexed_data(INP t_segment_inf * segment_inf, +void alloc_and_load_rr_indexed_data(INP const t_segment_inf * segment_inf, INP int num_segment, INP t_ivec *** L_rr_node_indices, INP int nodes_per_chan, int wire_to_ipin_switch, enum e_base_cost_type base_cost_type) { @@ -258,7 +258,7 @@ static float get_average_opin_delay(t_ivec *** L_rr_node_indices, static void load_rr_indexed_data_T_values(int index_start, int num_indices_to_load, t_rr_type rr_type, int nodes_per_chan, - t_ivec *** L_rr_node_indices, t_segment_inf * segment_inf) { + t_ivec *** L_rr_node_indices, const t_segment_inf * segment_inf) { /* Loads the average propagation times through segments of each index type * * for either all CHANX segment types or all CHANY segment types. It does * diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.h b/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.h index 1ec5ca8ab..e5c03aa9f 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.h +++ b/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.h @@ -1,3 +1,3 @@ -void alloc_and_load_rr_indexed_data(t_segment_inf * segment_inf, +void alloc_and_load_rr_indexed_data(const t_segment_inf * segment_inf, int num_segment, t_ivec *** L_rr_node_indices, int nodes_per_chan, int wire_to_ipin_switch, enum e_base_cost_type base_cost_type); diff --git a/vpr7_x2p/vpr/SRC/util/vpr_utils.c b/vpr7_x2p/vpr/SRC/util/vpr_utils.c index a7c1dbf3a..93ef9fe24 100755 --- a/vpr7_x2p/vpr/SRC/util/vpr_utils.c +++ b/vpr7_x2p/vpr/SRC/util/vpr_utils.c @@ -1165,8 +1165,8 @@ void alloc_and_load_idirect_from_blk_pin(t_direct_inf* directs, int num_directs, * This data structure supplements the the info in the "directs" data structure * TODO: The function that does this parsing in placement is poorly done because it lacks generality on heterogeniety, should replace with this one */ -t_clb_to_clb_directs * alloc_and_load_clb_to_clb_directs(INP t_direct_inf *directs, - INP int num_directs) { +t_clb_to_clb_directs * alloc_and_load_clb_to_clb_directs(INP const t_direct_inf *directs, + INP const int num_directs) { int i, j; t_clb_to_clb_directs *clb_to_clb_directs; char *pb_type_name, *port_name; diff --git a/vpr7_x2p/vpr/SRC/util/vpr_utils.h b/vpr7_x2p/vpr/SRC/util/vpr_utils.h index 51eb05da9..721b7dec1 100755 --- a/vpr7_x2p/vpr/SRC/util/vpr_utils.h +++ b/vpr7_x2p/vpr/SRC/util/vpr_utils.h @@ -41,7 +41,7 @@ void alloc_and_load_idirect_from_blk_pin(t_direct_inf* directs, int num_directs, void parse_direct_pin_name(char * src_string, int line, int * start_pin_index, int * end_pin_index, char * pb_type_name, char * port_name); -t_clb_to_clb_directs *alloc_and_load_clb_to_clb_directs(INP t_direct_inf *directs, INP int num_directs); +t_clb_to_clb_directs *alloc_and_load_clb_to_clb_directs(INP const t_direct_inf *directs, INP const int num_directs); void free_cb(t_pb *pb);