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 54cea15ea..58010142e 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,7 +56,6 @@ #include "ReadOptions.h" #include "rr_graph.h" #include "rr_graph2.h" -#include "rr_graph_tileable_sbox.h" #include "route_common.h" #include "fpga_x2p_types.h" #include "rr_graph_tileable_builder.h" @@ -66,6 +65,13 @@ #include "rr_blocks.h" #include "chan_node_details.h" #include "device_coordinator.h" +#include "rr_graph_tileable_sbox.h" + +/************************************************************************ + * Local data stuctures in the file + ***********************************************************************/ +typedef std::vector>> t_track2pin_map; +typedef std::vector>> t_pin2track_map; /************************************************************************ * Local function in the file @@ -538,8 +544,11 @@ 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, - t_rr_graph* rr_graph, size_t* cur_node_id) { + const t_grid_tile& cur_grid, + enum e_side io_side, + t_rr_graph* rr_graph, + size_t* cur_node_id, + int wire_to_ipin_switch, int delayless_switch) { Side io_side_manager(io_side); /* Walk through the height of each grid, * get pins and configure the rr_nodes */ @@ -565,6 +574,10 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; + /* cost index is a FIXED value for OPIN */ + rr_graph->rr_node[*cur_node_id].cost_index = OPIN_COST_INDEX; + /* Switch info */ + rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch; /* fill fast look-up table */ load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, rr_graph->rr_node[*cur_node_id].type, @@ -586,6 +599,10 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; + /* cost index is a FIXED value for IPIN */ + rr_graph->rr_node[*cur_node_id].cost_index = IPIN_COST_INDEX; + /* Switch info */ + rr_graph->rr_node[*cur_node_id].driver_switch = wire_to_ipin_switch; /* fill fast look-up table */ load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, rr_graph->rr_node[*cur_node_id].type, @@ -612,6 +629,15 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator /* FIXME: need to confirm if the capacity should be the number of pins in this class*/ rr_graph->rr_node[*cur_node_id].capacity = cur_grid.type->class_inf[iclass].num_pins; rr_graph->rr_node[*cur_node_id].occ = 0; + /* cost index is a FIXED value for SOURCE and SINK */ + if (SOURCE == rr_graph->rr_node[*cur_node_id].type) { + rr_graph->rr_node[*cur_node_id].cost_index = SOURCE_COST_INDEX; + } + if (SINK == rr_graph->rr_node[*cur_node_id].type) { + rr_graph->rr_node[*cur_node_id].cost_index = SINK_COST_INDEX; + } + /* Switch info */ + rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch; /* TODO: should we set pb_graph_pin here? */ /* fill fast look-up table */ load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, @@ -635,8 +661,10 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator ***********************************************************************/ static void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator, - t_rr_type chan_type, + const t_rr_type chan_type, ChanNodeDetails* chan_details, + const std::vector segment_infs, + const int cost_index_offset, t_rr_graph* rr_graph, size_t* cur_node_id) { /* Check each node_id(potential ptc_num) in the channel : @@ -657,8 +685,13 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator rr_graph->rr_node[*cur_node_id].track_ids.push_back(itrack); rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; + /* assign switch id */ + size_t seg_id = chan_details->get_track_segment_id(itrack); + rr_graph->rr_node[*cur_node_id].driver_switch = segment_infs[seg_id].opin_switch; /* Update chan_details with node_id */ chan_details->set_track_node_id(itrack, *cur_node_id); + /* cost index depends on the segment index */ + rr_graph->rr_node[*cur_node_id].cost_index = cost_index_offset + seg_id; /* Update node counter */ (*cur_node_id)++; /* Finish here, go to next */ @@ -677,6 +710,11 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator rr_graph->rr_node[*cur_node_id].occ = 0; /* Update chan_details with node_id */ chan_details->set_track_node_id(itrack, *cur_node_id); + /* assign switch id */ + size_t seg_id = chan_details->get_track_segment_id(itrack); + rr_graph->rr_node[*cur_node_id].driver_switch = segment_infs[seg_id].opin_switch; + /* cost index depends on the segment index */ + rr_graph->rr_node[*cur_node_id].cost_index = cost_index_offset + seg_id; /* Update node counter */ (*cur_node_id)++; /* Finish here, go to next */ @@ -755,7 +793,8 @@ 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) { + std::vector segment_infs, + int wire_to_ipin_switch, int delayless_switch) { /* counter */ size_t cur_node_id = 0; /* configure by node type */ @@ -780,7 +819,8 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, } /* Configure rr_nodes for this grid */ load_one_grid_rr_nodes_basic_info(grid_coordinator, grid[ix][iy], io_side, - rr_graph, &cur_node_id); + rr_graph, &cur_node_id, + wire_to_ipin_switch, delayless_switch); } } @@ -799,7 +839,10 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, } ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, chan_side, segment_infs); /* Configure CHANX in this channel */ - load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, &chanx_details, + load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, + &chanx_details, + segment_infs, + CHANX_COST_INDEX_START, rr_graph, &cur_node_id); /* Rotate the chanx_details by an offset of 1*/ /* For INC_DIRECTION, we use clockwise rotation @@ -834,7 +877,10 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, } ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, chan_side, segment_infs); /* Configure CHANX in this channel */ - load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, &chany_details, + load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, + &chany_details, + segment_infs, + CHANX_COST_INDEX_START + segment_infs.size(), rr_graph, &cur_node_id); /* Rotate the chany_details by an offset of 1*/ /* For INC_DIRECTION, we use clockwise rotation @@ -1341,11 +1387,9 @@ void add_one_edge_for_two_rr_nodes(t_rr_graph* rr_graph, ***********************************************************************/ static void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, - std::vector < std::vector< std::vector > > track2ipin_lookup, - std::vector < std::vector< std::vector > > opin2track_map, - std::vector < std::vector< std::vector > > sb_conn, - int num_directs, t_clb_to_clb_directs* clb_to_clb_directs, - int num_switches, int delayless_switch) { + t_track2pin_map track2ipin_map, + t_pin2track_map opin2track_map, + t_track2track_map track2track_map) { /* Check rr_gsb */ assert (NULL != rr_gsb); @@ -1353,6 +1397,7 @@ void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, 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); @@ -1362,42 +1407,69 @@ void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, 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, - delayless_switch); + 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); - /* 2. create edges between IPINs and SINKs */ + /* 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, - delayless_switch); + 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); + } } } - /* 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) */ - /* For TOP and BOTTOM */ - - return; } /************************************************************************ - * Convert the track_to_ipin_look[0..nodes_per_chan-1][0..height][0..3][pin_numbers] + * 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 - * track2ipin_lookup[gsb_side][0..chan_width-1][ipin_indices] + * pin2track_map[gsb_side][0..chan_width-1][ipin_indices] ***********************************************************************/ static -std::vector < std::vector< std::vector > > build_gsb_track_to_ipin_lookup(const RRGSB& rr_gsb, - std::vector< std::vector > grids, - int** Fc_in, - int***** ipin_to_track_map) { - std::vector < std::vector< std::vector > > track2ipin_lookup; /* [0..gsb_side][0..num_tracks][0..Fc-1] */ +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 */ - track2ipin_lookup.resize(rr_gsb.get_num_sides()); + pin2track_map.resize(rr_gsb.get_num_sides()); /* Walk through each side */ for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { @@ -1405,28 +1477,151 @@ std::vector < std::vector< std::vector > > build_gsb_track_to_ipin_lookup(c 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); - track2ipin_lookup[side].resize(chan_width); - /* Find the ipin nodes */ - 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); + 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[ipin_node->xlow][ipin_node->ylow].type->index; - int offset = grid[ipin_node->xlow][ipin_node->ylow].offset; - enum e_side pin_side = rr_gsb.get_ipin_node_grid_side(gsb_side, inode); + 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 == ipin_to_track_map[grid_type_id][ipin_node->ptc_num][offset][0]) { + 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_in[grid_type_id][ipin_node->ptc_num]; ++iconn) { - int track_id = ipin_to_track_map[grid_type_id][ipin_node->ptc_num][offset][pin_side][iconn]; - track2ipin_lookup[gsb_side][track_id].push_back(inode); + 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 track2ipin_lookup; + 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; } @@ -1448,31 +1643,36 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, std::vector< std::vector > grids, std::vector device_chan_width, std::vector segment_inf, - int L_num_types, t_type_ptr types, int** Fc_in, int** Fc_out, int***** ipin_to_track_map, int***** opin_to_track_map, - vtr::NdMatrix,3> switch_block_conn, - int num_directs, t_clb_to_clb_directs* clb_to_clb_directs, - int num_switches, int delayless_switch) { + enum e_switch_block_type sb_type, int Fs) { + DeviceCoordinator device_range(device_size.get_x() - 1, device_size.get_y() - 1); + /* Go Switch Block by Switch Block */ for (size_t ix = 0; ix < device_size.get_x(); ++ix) { for (size_t iy = 0; iy < device_size.get_y(); ++iy) { + DeviceCoordinator gsb_coordinator(ix, iy); /* Create a GSB object */ RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); + /* adapt the track_to_ipin_lookup for the GSB nodes */ - std::vector < std::vector< std::vector > > track2ipin_lookup; /* [0..gsb_side][0..num_tracks][0..Fc-1] */ - track2ipin_lookup = build_gsb_track_to_ipin_lookup(rr_gsb, grids, Fc_in, ipin_to_track_map); + 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); + /* adapt the opin_to_track_map for the GSB nodes */ - std::vector < std::vector< std::vector > > opin2track_map; /* [0..gsb_side][0..num_opin_node][0..Fc-1] */ + 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); + /* adapt the switch_block_conn for the GSB nodes */ - std::vector < std::vector< std::vector > > sb_conn; /* [0..from_gsb_side][0..to_gsb_side][0..chan_width-1] */ + t_track2track_map sb_conn; /* [0..from_gsb_side][0..chan_width-1][track_indices] */ + sb_conn = build_gsb_track_to_track_map(rr_graph, rr_gsb, sb_type, Fs, segment_inf); + /* Build edges for a GSB */ build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, - track2ipin_lookup, opin2track_map, sb_conn, - num_directs, clb_to_clb_directs, - num_switches, delayless_switch); + ipin2track_map, opin2track_map, + sb_conn); /* Finish this GSB, go to the next*/ } } @@ -1480,6 +1680,39 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, return; } +/************************************************************************ + * Build direct edges for Grids * + ***********************************************************************/ +static +void build_rr_graph_direct_connections(t_rr_graph* rr_graph, + const DeviceCoordinator& device_size, + std::vector< std::vector > grids, + const int delayless_switch, + const int num_directs, + const t_direct_inf *directs, + const t_clb_to_clb_directs *clb_to_clb_directs) { + for (size_t ix = 0; ix < device_size.get_x(); ++ix) { + for (size_t iy = 0; iy < device_size.get_y(); ++iy) { + /* Skip EMPTY tiles */ + if (EMPTY_TYPE == grids[ix][iy].type) { + continue; + } + /* Skip height>1 tiles (mostly heterogeneous blocks) */ + if (0 < grids[ix][iy].offset) { + continue; + } + DeviceCoordinator from_grid_coordinator(ix, iy); + build_direct_connections_for_one_gsb(rr_graph, device_size, + from_grid_coordinator, + grids[ix][iy], + delayless_switch, + num_directs, directs, clb_to_clb_directs); + } + } + + return; +} + /************************************************************************ * Main function of this file * Builder for a detailed uni-directional tileable rr_graph @@ -1524,7 +1757,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, 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 int num_switches, INP t_segment_inf * segment_inf, + 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, @@ -1593,14 +1826,15 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, * grid_info : pb_graph_pin ***********************************************************************/ alloc_rr_graph_fast_lookup(device_size, &rr_graph); - load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs); + load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs, + wire_to_ipin_switch, delayless_switch); /************************************************************************ - * 3.1 Create the connectivity of OPINs + * 5.1 Create the connectivity of OPINs * a. Evenly assign connections to OPINs to routing tracks * b. the connection pattern should be same across the fabric * - * 3.2 Create the connectivity of IPINs + * 5.2 Create the connectivity of IPINs * a. Evenly assign connections from routing tracks to IPINs * b. the connection pattern should be same across the fabric ***********************************************************************/ @@ -1639,11 +1873,6 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, opin_to_track_map[i] = alloc_and_load_pin_to_track_map(DRIVER, chan_width, Fc_out[i], &types[i], FALSE, UNI_DIRECTIONAL); } - /************************************************************************ - * 4. Build switch block connection matrix - ***********************************************************************/ - vtr::NdMatrix,3> switch_block_conn = alloc_and_load_tileable_switch_block_conn(chan_width, sb_type, Fs); - /************************************************************************ * 6. Build the connections tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure @@ -1652,19 +1881,25 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, * In addition, we will also handle direct-connections: * Add edges that bridge OPINs and IPINs to the rr_graph ***********************************************************************/ + + /* 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, + sb_type, Fs); + + /************************************************************************ + * 7. Build direction connection lists + ***********************************************************************/ /* Create data structure of direct-connections */ t_clb_to_clb_directs* clb_to_clb_directs = NULL; if (num_directs > 0) { clb_to_clb_directs = alloc_and_load_clb_to_clb_directs(directs, num_directs); } - - /* Create edges for a tileable rr_graph */ - build_rr_graph_edges(&rr_graph, device_size, grids, device_chan_width, segment_infs, - L_num_types, types, Fc_in, Fc_out, ipin_to_track_map, opin_to_track_map, switch_block_conn, - num_directs, clb_to_clb_directs, num_switches, delayless_switch); + build_rr_graph_direct_connections(&rr_graph, device_size, grids, delayless_switch, + num_directs, directs, clb_to_clb_directs); /************************************************************************ - * 7. Allocate external data structures + * 8. Allocate external data structures * a. cost_index * b. RC tree ***********************************************************************/ @@ -1672,7 +1907,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, wire_to_ipin_switch, base_cost_type); /************************************************************************ - * 8. Sanitizer for the rr_graph, check connectivities of rr_nodes + * 9. Sanitizer for the rr_graph, check connectivities of rr_nodes ***********************************************************************/ /* We set global variables for rr_nodes here, @@ -1682,7 +1917,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, rr_node_indices = rr_graph.rr_node_indices; /************************************************************************ - * 9. Free all temp stucts + * 10. Free all temp stucts ***********************************************************************/ /* Free all temp structs */ 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 04694f492..26e1f9cc7 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 @@ -6,7 +6,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, 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 int num_switches, INP t_segment_inf * segment_inf, + 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, 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 index f30ceed2d..df894c81a 100755 --- 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 @@ -1,211 +1,461 @@ -#include "vtr_assert.h" +/********************************************************** + * 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. + ***********************************************************************/ -#include "vtr_util.h" -#include "vtr_memory.h" +/************************************************************************ + * 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" -#include "rr_graph_util.h" -#include "ReadOptions.h" - -static -int get_tileable_simple_switch_block_track(const enum e_side from_side, - const enum e_side to_side, const int from_track, - const enum e_switch_block_type switch_block_type, const int nodes_per_chan); /************************************************************************ - * Build internal connection pattern for a switch block - * This function is adapt to fit the tileable routing context from - * rr_graph_sbox.c : alloc_and_load_switch_block_conn - * Switch box: * - * TOP (CHANY) * - * | | | | | | * - * +-----------+ * - * --| |-- * - * --| |-- * - * LEFT --| |-- RIGHT * - * (CHANX)--| |--(CHANX) * - * --| |-- * - * --| |-- * - * +-----------+ * - * | | | | | | * - * BOTTOM (CHANY) * - * - * [0..3][0..3][0..nodes_per_chan-1]. Structure below is indexed as: * - * [from_side][to_side][from_track]. That yields an integer vector (ivec) * - * of the tracks to which from_track connects in the proper to_location. * - * For simple switch boxes this is overkill, but it will allow complicated * - * switch boxes with Fs > 3, etc. without trouble. * + * Internal data structures ***********************************************************************/ +typedef std::vector> t_track_group; -/* Allocates and loads the switch_block_conn data structure. This structure * - * lists which tracks connect to which at each switch block. This is for - * bidir. */ -vtr::NdMatrix,3> alloc_and_load_tileable_switch_block_conn(const size_t nodes_per_chan, - const e_switch_block_type switch_block_type, - const int Fs) { +/************************************************************************ + * 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 */ +}; - /* Currently Fs must be 3 since each track maps once to each other side */ - VTR_ASSERT(3 == Fs); - - vtr::NdMatrix,3> switch_block_conn({4, 4, nodes_per_chan}); - - for (e_side from_side : {TOP, RIGHT, BOTTOM, LEFT}) { - for (e_side to_side : {TOP, RIGHT, BOTTOM, LEFT}) { - for (size_t from_track = 0; from_track < nodes_per_chan; from_track++) { - if (from_side != to_side) { - switch_block_conn[from_side][to_side][from_track].resize(1); - - switch_block_conn[from_side][to_side][from_track][0] = get_tileable_simple_switch_block_track(from_side, to_side, - from_track, switch_block_type, nodes_per_chan); - } else { /* from_side == to_side -> no connection. */ - switch_block_conn[from_side][to_side][from_track].clear(); - } - } - } - } - - if (getEchoEnabled()) { - FILE *out = vtr::fopen("switch_block_conn.echo", "w"); - for (int l = 0; l < 4; ++l) { - for (int k = 0; k < 4; ++k) { - fprintf(out, "Side %d to %d\n", l, k); - for (size_t j = 0; j < nodes_per_chan; ++j) { - fprintf(out, "%zu: ", j); - for (unsigned i = 0; i < switch_block_conn[l][k][j].size(); ++i) { - fprintf(out, "%d ", switch_block_conn[l][k][j][i]); - } - fprintf(out, "\n"); - } - fprintf(out, "\n"); - } - } - fclose(out); - } - return switch_block_conn; -} - -#define SBOX_ERROR -1 - -/* This routine permutes the track number to connect for topologies - * SUBSET, UNIVERSAL, and WILTON. I added FULL (for fully flexible topology) - * but the returned value is simply a dummy, since we don't need to permute - * what connections to make for FULL (connect to EVERYTHING) */ +/************************************************************************ + * 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 -int get_tileable_simple_switch_block_track(const enum e_side from_side, - const enum e_side to_side, const int from_track, - const enum e_switch_block_type switch_block_type, const int nodes_per_chan) { +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); - /* This routine returns the track number to which the from_track should * - * connect. It supports three simple, Fs = 3, switch blocks. */ - - int to_track = SBOX_ERROR; /* Can check to see if it's not set later. */ - - if (switch_block_type == SUBSET) { /* NB: Global routing uses SUBSET too */ - to_track = from_track; + /* 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; } - /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ - - else if (switch_block_type == WILTON) { - - if (from_side == LEFT) { - - if (to_side == RIGHT) { /* CHANX to CHANX */ - to_track = from_track; - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_track = (nodes_per_chan - (from_track % nodes_per_chan)) % nodes_per_chan; - } else if (to_side == BOTTOM) { - to_track = (nodes_per_chan + from_track - 1) % nodes_per_chan; - } - } - - else if (from_side == RIGHT) { - if (to_side == LEFT) { /* CHANX to CHANX */ - to_track = from_track; - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_track = (nodes_per_chan + from_track - 1) % nodes_per_chan; - } else if (to_side == BOTTOM) { - to_track = (2 * nodes_per_chan - 2 - from_track) % nodes_per_chan; - } - } - - else if (from_side == BOTTOM) { - if (to_side == TOP) { /* CHANY to CHANY */ - to_track = from_track; - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_track = (from_track + 1) % nodes_per_chan; - } else if (to_side == RIGHT) { - to_track = (2 * nodes_per_chan - 2 - from_track) % nodes_per_chan; - } - } - - else if (from_side == TOP) { - if (to_side == BOTTOM) { /* CHANY to CHANY */ - to_track = from_track; - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_track = (nodes_per_chan - (from_track % nodes_per_chan)) % nodes_per_chan; - } else if (to_side == RIGHT) { - to_track = (from_track + 1) % nodes_per_chan; - } - } - - /* Force to_track to UN_SET if it falls outside the min/max channel width range */ - if (to_track < 0 || to_track >= nodes_per_chan) { - to_track = -1; - } - } - /* End switch_block_type == WILTON case. */ - else if (switch_block_type == UNIVERSAL) { - - if (from_side == LEFT) { - - if (to_side == RIGHT) { /* CHANX to CHANX */ - to_track = from_track; - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_track = nodes_per_chan - 1 - from_track; - } else if (to_side == BOTTOM) { - to_track = from_track; - } - } - - else if (from_side == RIGHT) { - if (to_side == LEFT) { /* CHANX to CHANX */ - to_track = from_track; - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_track = from_track; - } else if (to_side == BOTTOM) { - to_track = nodes_per_chan - 1 - from_track; - } - } - - else if (from_side == BOTTOM) { - if (to_side == TOP) { /* CHANY to CHANY */ - to_track = from_track; - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_track = from_track; - } else if (to_side == RIGHT) { - to_track = nodes_per_chan - 1 - from_track; - } - } - - else if (from_side == TOP) { - if (to_side == BOTTOM) { /* CHANY to CHANY */ - to_track = from_track; - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_track = nodes_per_chan - 1 - from_track; - } else if (to_side == RIGHT) { - to_track = from_track; - } - } - } - - /* End switch_block_type == UNIVERSAL case. */ - /* UDSD Modification by WMF Begin */ - if (switch_block_type == FULL) { /* Just a placeholder. No meaning in reality */ - to_track = from_track; - } - /* UDSD Modification by WMF End */ - - return (to_track); + 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 index 93f3ea5ea..3079cbea8 100755 --- 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 @@ -5,8 +5,16 @@ #include "vtr_ndmatrix.h" -vtr::NdMatrix,3> alloc_and_load_tileable_switch_block_conn(size_t nodes_per_chan, - enum e_switch_block_type switch_block_type, int Fs); +#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/fpga_x2p_types.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_types.h index 6a53c32c9..796707d78 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_types.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_types.h @@ -1,3 +1,8 @@ +#ifndef FPGA_X2P_TYPES_H +#define FPGA_X2P_TYPES_H + +#include "route_common.h" + /* Define the basic data structures used for FPGA-SPICE */ /* Default ID of switch used in rr_node */ @@ -135,3 +140,4 @@ struct fpga_spice_phy_pb { int num_iopads; }; +#endif diff --git a/vpr7_x2p/vpr/SRC/route/route_common.h b/vpr7_x2p/vpr/SRC/route/route_common.h index f3be76474..272791041 100755 --- a/vpr7_x2p/vpr/SRC/route/route_common.h +++ b/vpr7_x2p/vpr/SRC/route/route_common.h @@ -1,3 +1,6 @@ +#ifndef ROUTE_COMMON_H +#define ROUTE_COMMON_H + /************ Defines and types shared by all route files ********************/ typedef struct s_heap t_heap; @@ -118,4 +121,4 @@ void auto_detect_and_reserve_locally_used_opins(float pres_fac, boolean rip_up_l void free_chunk_memory_trace(void); - +#endif