bug fixing and reorganize rr_graph builder source files
This commit is contained in:
parent
2837f44df2
commit
59df305668
|
@ -36,6 +36,7 @@
|
|||
#include "arch_types.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
/*******************************************************************************
|
||||
* Global data types and constants
|
||||
|
@ -908,6 +909,10 @@ typedef enum e_rr_type {
|
|||
SOURCE = 0, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES
|
||||
} t_rr_type;
|
||||
|
||||
constexpr std::array<const char*, NUM_RR_TYPES + 1> rr_node_typename { {
|
||||
"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY", "INTRA_CLUSTER_EDGE", "NUM_RR_TYPES"
|
||||
} };
|
||||
|
||||
/* Type of a routing resource node. x-directed channel segment, *
|
||||
* y-directed channel segment, input pin to a clb to pad, output *
|
||||
* from a clb or pad (i.e. output pin of a net) and: *
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
/**********************************************************
|
||||
* 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_builder_utils.cpp
|
||||
* Created by: Xifan Tang
|
||||
* Change history:
|
||||
* +-------------------------------------+
|
||||
* | Date | Author | Notes
|
||||
* +-------------------------------------+
|
||||
* | 2019/06/23 | Xifan Tang | Created
|
||||
* +-------------------------------------+
|
||||
***********************************************************************/
|
||||
/************************************************************************
|
||||
* This file contains most utilized functions for rr_graph builders
|
||||
***********************************************************************/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rr_graph_builder_utils.h"
|
||||
#include "globals.h"
|
||||
|
||||
/************************************************************************
|
||||
* Initialize a rr_node
|
||||
************************************************************************/
|
||||
void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node) {
|
||||
cur_rr_node->xlow = 0;
|
||||
cur_rr_node->xhigh = 0;
|
||||
cur_rr_node->ylow = 0;
|
||||
cur_rr_node->xhigh = 0;
|
||||
|
||||
cur_rr_node->ptc_num = 0;
|
||||
cur_rr_node->track_ids.clear();
|
||||
|
||||
cur_rr_node->cost_index = 0;
|
||||
cur_rr_node->occ = 0;
|
||||
cur_rr_node->fan_in = 0;
|
||||
cur_rr_node->num_edges = 0;
|
||||
cur_rr_node->type = NUM_RR_TYPES;
|
||||
cur_rr_node->edges = NULL;
|
||||
cur_rr_node->switches = NULL;
|
||||
|
||||
cur_rr_node->driver_switch = 0;
|
||||
cur_rr_node->unbuf_switched = 0;
|
||||
cur_rr_node->buffered = 0;
|
||||
cur_rr_node->R = 0.;
|
||||
cur_rr_node->C = 0.;
|
||||
|
||||
cur_rr_node->direction = BI_DIRECTION; /* Give an invalid value, easy to check errors */
|
||||
cur_rr_node->drivers = SINGLE;
|
||||
cur_rr_node->num_wire_drivers = 0;
|
||||
cur_rr_node->num_opin_drivers = 0;
|
||||
|
||||
cur_rr_node->num_drive_rr_nodes = 0;
|
||||
cur_rr_node->drive_rr_nodes = NULL;
|
||||
cur_rr_node->drive_switches = NULL;
|
||||
|
||||
cur_rr_node->vpack_net_num_changed = FALSE;
|
||||
cur_rr_node->is_parasitic_net = FALSE;
|
||||
cur_rr_node->is_in_heap = FALSE;
|
||||
|
||||
cur_rr_node->sb_num_drive_rr_nodes = 0;
|
||||
cur_rr_node->sb_drive_rr_nodes = NULL;
|
||||
cur_rr_node->sb_drive_switches = NULL;
|
||||
|
||||
cur_rr_node->pb = NULL;
|
||||
|
||||
cur_rr_node->name_mux = NULL;
|
||||
cur_rr_node->id_path = -1;
|
||||
|
||||
cur_rr_node->prev_node = -1;
|
||||
cur_rr_node->prev_edge = -1;
|
||||
cur_rr_node->net_num = -1;
|
||||
cur_rr_node->vpack_net_num = -1;
|
||||
|
||||
cur_rr_node->prev_node_in_pack = -1;
|
||||
cur_rr_node->prev_edge_in_pack = -1;
|
||||
cur_rr_node->net_num_in_pack = -1;
|
||||
|
||||
cur_rr_node->pb_graph_pin = NULL;
|
||||
cur_rr_node->tnode = NULL;
|
||||
|
||||
cur_rr_node->pack_intrinsic_cost = 0.;
|
||||
cur_rr_node->z = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Get the class index of a grid pin
|
||||
***********************************************************************/
|
||||
int get_grid_pin_class_index(const t_grid_tile& cur_grid,
|
||||
const int pin_index) {
|
||||
/* check */
|
||||
assert ( pin_index < cur_grid.type->num_pins);
|
||||
return cur_grid.type->pin_class[pin_index];
|
||||
}
|
||||
|
||||
/* Deteremine the side of a io grid */
|
||||
enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size,
|
||||
const DeviceCoordinator& grid_coordinator) {
|
||||
/* TOP side IO of FPGA */
|
||||
if (device_size.get_y() == grid_coordinator.get_y()) {
|
||||
return BOTTOM; /* Such I/O has only Bottom side pins */
|
||||
} else if (device_size.get_x() == grid_coordinator.get_x()) { /* RIGHT side IO of FPGA */
|
||||
return LEFT; /* Such I/O has only Left side pins */
|
||||
} else if (0 == grid_coordinator.get_y()) { /* BOTTOM side IO of FPGA */
|
||||
return TOP; /* Such I/O has only Top side pins */
|
||||
} else if (0 == grid_coordinator.get_x()) { /* LEFT side IO of FPGA */
|
||||
return RIGHT; /* Such I/O has only Right side pins */
|
||||
} else {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) I/O Grid is in the center part of FPGA! Currently unsupported!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Get a list of pin_index for a grid (either OPIN or IPIN)
|
||||
* For IO_TYPE, only one side will be used, we consider one side of pins
|
||||
* For others, we consider all the sides
|
||||
***********************************************************************/
|
||||
std::vector<int> 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<int> pin_list;
|
||||
/* Make sure a clear start */
|
||||
pin_list.clear();
|
||||
|
||||
for (int ipin = 0; ipin < cur_grid.type->num_pins; ++ipin) {
|
||||
int class_id = cur_grid.type->pin_class[ipin];
|
||||
if ( (1 == cur_grid.type->pinloc[pin_height][pin_side][ipin])
|
||||
&& (pin_type == cur_grid.type->class_inf[class_id].type) ) {
|
||||
pin_list.push_back(ipin);
|
||||
}
|
||||
}
|
||||
return pin_list;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Get the number of pins for a grid (either OPIN or IPIN)
|
||||
* For IO_TYPE, only one side will be used, we consider one side of pins
|
||||
* For others, we consider all the sides
|
||||
***********************************************************************/
|
||||
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 */
|
||||
for (size_t side = 0; side < NUM_SIDES; ++side) {
|
||||
Side side_manager(side);
|
||||
/* skip unwanted sides */
|
||||
if ( (IO_TYPE == cur_grid.type)
|
||||
&& (side != io_side_manager.to_size_t()) ) {
|
||||
continue;
|
||||
}
|
||||
/* Get pin list */
|
||||
for (int height = 0; height < cur_grid.type->height; ++height) {
|
||||
std::vector<int> pin_list = get_grid_side_pins(cur_grid, pin_type, side_manager.get_side(), height);
|
||||
num_pins += pin_list.size();
|
||||
}
|
||||
}
|
||||
|
||||
return num_pins;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Get the number of pins for a grid (either OPIN or IPIN)
|
||||
* For IO_TYPE, only one side will be used, we consider one side of pins
|
||||
* For others, we consider all the sides
|
||||
***********************************************************************/
|
||||
size_t get_grid_num_classes(const t_grid_tile& cur_grid,
|
||||
const enum e_pin_type pin_type) {
|
||||
size_t num_classes = 0;
|
||||
|
||||
for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) {
|
||||
/* Bypass unmatched pin_type */
|
||||
if (pin_type != cur_grid.type->class_inf[iclass].type) {
|
||||
continue;
|
||||
}
|
||||
num_classes++;
|
||||
}
|
||||
|
||||
return num_classes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* 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
|
||||
***********************************************************************/
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef RR_GRAPH_BUILDER_UTILS_H
|
||||
#define RR_GRAPH_BUILDER_UTILS_H
|
||||
|
||||
#include "vpr_types.h"
|
||||
#include "fpga_x2p_types.h"
|
||||
#include "device_coordinator.h"
|
||||
|
||||
void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node);
|
||||
|
||||
int get_grid_pin_class_index(const t_grid_tile& cur_grid,
|
||||
const int pin_index);
|
||||
|
||||
enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size,
|
||||
const DeviceCoordinator& grid_coordinator);
|
||||
|
||||
std::vector<int> 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);
|
||||
|
||||
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 get_grid_num_classes(const t_grid_tile& cur_grid,
|
||||
const enum e_pin_type pin_type);
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
/**********************************************************
|
||||
* 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: tileable_chan_details_builder.cpp
|
||||
* Created by: Xifan Tang
|
||||
* Change history:
|
||||
* +-------------------------------------+
|
||||
* | Date | Author | Notes
|
||||
* +-------------------------------------+
|
||||
* | 2019/06/23 | Xifan Tang | Created
|
||||
* +-------------------------------------+
|
||||
***********************************************************************/
|
||||
/************************************************************************
|
||||
* This file contains a builder for the ChanNodeDetails data structure
|
||||
* Different from VPR rr_graph builders, this builder aims to create a
|
||||
* highly regular routing channel. Thus, it is called tileable,
|
||||
* which brings significant advantage in producing large FPGA fabrics.
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "tileable_chan_details_builder.h"
|
||||
|
||||
/************************************************************************
|
||||
* Generate the number of tracks for each types of routing segments
|
||||
* w.r.t. the frequency of each of segments and channel width
|
||||
* Note that if we dertermine the number of tracks per type using
|
||||
* chan_width * segment_frequency / total_freq may cause
|
||||
* The total track num may not match the chan_width,
|
||||
* therefore, we assign tracks one by one until we meet the frequency requirement
|
||||
* In this way, we can assign the number of tracks with repect to frequency
|
||||
***********************************************************************/
|
||||
static
|
||||
std::vector<size_t> get_num_tracks_per_seg_type(const size_t chan_width,
|
||||
const std::vector<t_segment_inf> segment_inf,
|
||||
const bool use_full_seg_groups) {
|
||||
std::vector<size_t> result;
|
||||
std::vector<double> demand;
|
||||
/* Make sure a clean start */
|
||||
result.resize(segment_inf.size());
|
||||
demand.resize(segment_inf.size());
|
||||
|
||||
/* Scale factor so we can divide by any length
|
||||
* and still use integers */
|
||||
/* Get the sum of frequency */
|
||||
size_t scale = 1;
|
||||
size_t freq_sum = 0;
|
||||
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
|
||||
scale *= segment_inf[iseg].length;
|
||||
freq_sum += segment_inf[iseg].frequency;
|
||||
}
|
||||
size_t reduce = scale * freq_sum;
|
||||
|
||||
/* Init assignments to 0 and set the demand values */
|
||||
/* Get the fraction of each segment type considering the frequency:
|
||||
* num_track_per_seg = chan_width * (freq_of_seg / sum_freq)
|
||||
*/
|
||||
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
|
||||
result[iseg] = 0;
|
||||
demand[iseg] = scale * chan_width * segment_inf[iseg].frequency;
|
||||
if (true == use_full_seg_groups) {
|
||||
demand[iseg] /= segment_inf[iseg].length;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if the sum of num_tracks, matches the chan_width */
|
||||
/* Keep assigning tracks until we use them up */
|
||||
size_t assigned = 0;
|
||||
size_t size = 0;
|
||||
size_t imax = 0;
|
||||
while (assigned < chan_width) {
|
||||
/* Find current maximum demand */
|
||||
double max = 0;
|
||||
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
|
||||
if (demand[iseg] > max) {
|
||||
imax = iseg;
|
||||
}
|
||||
max = std::max(demand[iseg], max);
|
||||
}
|
||||
|
||||
/* Assign tracks to the type and reduce the types demand */
|
||||
size = (use_full_seg_groups ? segment_inf[imax].length : 1);
|
||||
demand[imax] -= reduce;
|
||||
result[imax] += size;
|
||||
assigned += size;
|
||||
}
|
||||
|
||||
/* Undo last assignment if we were closer to goal without it */
|
||||
if ((assigned - chan_width) > (size / 2)) {
|
||||
result[imax] -= size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Build details of routing tracks in a channel
|
||||
* The function will
|
||||
* 1. Assign the segments for each routing channel,
|
||||
* To be specific, for each routing track, we assign a routing segment.
|
||||
* The assignment is subject to users' specifications, such as
|
||||
* a. length of each type of segment
|
||||
* b. frequency of each type of segment.
|
||||
* c. routing channel width
|
||||
*
|
||||
* 2. The starting point of each segment in the channel will be assigned
|
||||
* For each segment group with same directionality (tracks have the same length),
|
||||
* every L track will be a starting point (where L denotes the length of segments)
|
||||
* In this case, if the number of tracks is not a multiple of L,
|
||||
* indeed we may have some <L segments. This can be considered as a side effect.
|
||||
* But still the rr_graph is tileable, which is the first concern!
|
||||
*
|
||||
* Here is a quick example of Length-4 wires in a W=12 routing channel
|
||||
* +---------------------------------------+--------------+
|
||||
* | Index | Direction | Starting Point | Ending Point |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 0 | MUX--------> | Yes | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 1 | <--------MUX | Yes | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 2 | --------> | No | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 3 | <-------- | No | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 4 | --------> | No | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 5 | <-------- | No | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 7 | -------->MUX | No | Yes |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 8 | MUX<-------- | No | Yes |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 9 | MUX--------> | Yes | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 10 | <--------MUX | Yes | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 11 | -------->MUX | No | Yes |
|
||||
* +------------------------------------------------------+
|
||||
* | 12 | <-------- | No | No |
|
||||
* +------------------------------------------------------+
|
||||
*
|
||||
* 3. SPECIAL for fringes: TOP|RIGHT|BOTTOM|RIGHT
|
||||
* if device_side is NUM_SIDES, we assume this channel does not locate on borders
|
||||
* All segments will start and ends with no exception
|
||||
*
|
||||
* 4. IMPORTANT: we should be aware that channel width maybe different
|
||||
* in X-direction and Y-direction channels!!!
|
||||
* So we will load segment details for different channels
|
||||
***********************************************************************/
|
||||
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<t_segment_inf> 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 != actual_chan_width % 2) {
|
||||
actual_chan_width++; /* increment it to be even */
|
||||
}
|
||||
assert (0 == actual_chan_width % 2);
|
||||
|
||||
/* Reserve channel width */
|
||||
chan_node_details.reserve(chan_width);
|
||||
/* Return if zero width is forced */
|
||||
if (0 == actual_chan_width) {
|
||||
return chan_node_details;
|
||||
}
|
||||
|
||||
/* Find the number of segments required by each group */
|
||||
std::vector<size_t> num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, TRUE);
|
||||
|
||||
/* Add node to ChanNodeDetails */
|
||||
size_t cur_track = 0;
|
||||
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
|
||||
/* segment length will be set to maxium segment length if this is a longwire */
|
||||
size_t seg_len = segment_inf[iseg].length;
|
||||
if (TRUE == segment_inf[iseg].longline) {
|
||||
seg_len = max_seg_length;
|
||||
}
|
||||
for (size_t itrack = 0; itrack < num_tracks[iseg]; ++itrack) {
|
||||
bool seg_start = false;
|
||||
bool seg_end = false;
|
||||
/* Every first track of a group of Length-N wires, we set a starting point */
|
||||
if (0 == itrack % seg_len) {
|
||||
seg_start = true;
|
||||
}
|
||||
/* Every last track of a group of Length-N wires, we set an ending point */
|
||||
if (seg_len - 1 == itrack % seg_len) {
|
||||
seg_end = true;
|
||||
}
|
||||
/* Since this is a unidirectional routing architecture,
|
||||
* Add a pair of tracks, 1 INC_DIRECTION track and 1 DEC_DIRECTION track
|
||||
*/
|
||||
chan_node_details.add_track(cur_track, INC_DIRECTION, iseg, seg_len, seg_start, seg_end);
|
||||
cur_track++;
|
||||
chan_node_details.add_track(cur_track, DEC_DIRECTION, iseg, seg_len, seg_start, seg_end);
|
||||
cur_track++;
|
||||
}
|
||||
}
|
||||
/* Check if all the tracks have been satisified */
|
||||
assert (cur_track == actual_chan_width);
|
||||
|
||||
/* If this is on the border of a device, segments should start */
|
||||
switch (device_side) {
|
||||
case TOP:
|
||||
case RIGHT:
|
||||
/* INC_DIRECTION should all end */
|
||||
chan_node_details.set_tracks_end(INC_DIRECTION);
|
||||
/* DEC_DIRECTION should all start */
|
||||
chan_node_details.set_tracks_start(DEC_DIRECTION);
|
||||
break;
|
||||
case BOTTOM:
|
||||
case LEFT:
|
||||
/* INC_DIRECTION should all start */
|
||||
chan_node_details.set_tracks_start(INC_DIRECTION);
|
||||
/* DEC_DIRECTION should all end */
|
||||
chan_node_details.set_tracks_end(DEC_DIRECTION);
|
||||
break;
|
||||
case NUM_SIDES:
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) Invalid device_side!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return chan_node_details;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef TILEABLE_CHAN_DETAILS_BUILDER_H
|
||||
#define TILEABLE_CHAN_DETAILS_BUILDER_H
|
||||
|
||||
#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<t_segment_inf> segment_inf);
|
||||
|
||||
#endif
|
|
@ -23,7 +23,7 @@
|
|||
***********************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Filename: rr_graph_tileable_builder.c
|
||||
* Filename: rr_graph_tileable_builder.cpp
|
||||
* Created by: Xifan Tang
|
||||
* Change history:
|
||||
* +-------------------------------------+
|
||||
|
@ -59,12 +59,15 @@
|
|||
#include "check_rr_graph.h"
|
||||
#include "route_common.h"
|
||||
#include "fpga_x2p_types.h"
|
||||
#include "rr_graph_tileable_builder.h"
|
||||
|
||||
#include "rr_blocks.h"
|
||||
#include "chan_node_details.h"
|
||||
#include "device_coordinator.h"
|
||||
#include "rr_graph_tileable_gsb.h"
|
||||
|
||||
#include "rr_graph_builder_utils.h"
|
||||
#include "tileable_chan_details_builder.h"
|
||||
#include "tileable_rr_graph_gsb.h"
|
||||
#include "tileable_rr_graph_builder.h"
|
||||
|
||||
/************************************************************************
|
||||
* Local data stuctures in the file
|
||||
|
@ -74,379 +77,6 @@
|
|||
* Local function in the file
|
||||
***********************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Initialize a rr_node
|
||||
************************************************************************/
|
||||
static
|
||||
void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node) {
|
||||
cur_rr_node->xlow = 0;
|
||||
cur_rr_node->xhigh = 0;
|
||||
cur_rr_node->ylow = 0;
|
||||
cur_rr_node->xhigh = 0;
|
||||
|
||||
cur_rr_node->ptc_num = 0;
|
||||
cur_rr_node->track_ids.clear();
|
||||
|
||||
cur_rr_node->cost_index = 0;
|
||||
cur_rr_node->occ = 0;
|
||||
cur_rr_node->fan_in = 0;
|
||||
cur_rr_node->num_edges = 0;
|
||||
cur_rr_node->type = NUM_RR_TYPES;
|
||||
cur_rr_node->edges = NULL;
|
||||
cur_rr_node->switches = NULL;
|
||||
|
||||
cur_rr_node->driver_switch = 0;
|
||||
cur_rr_node->unbuf_switched = 0;
|
||||
cur_rr_node->buffered = 0;
|
||||
cur_rr_node->R = 0.;
|
||||
cur_rr_node->C = 0.;
|
||||
|
||||
cur_rr_node->direction = BI_DIRECTION; /* Give an invalid value, easy to check errors */
|
||||
cur_rr_node->drivers = SINGLE;
|
||||
cur_rr_node->num_wire_drivers = 0;
|
||||
cur_rr_node->num_opin_drivers = 0;
|
||||
|
||||
cur_rr_node->num_drive_rr_nodes = 0;
|
||||
cur_rr_node->drive_rr_nodes = NULL;
|
||||
cur_rr_node->drive_switches = NULL;
|
||||
|
||||
cur_rr_node->vpack_net_num_changed = FALSE;
|
||||
cur_rr_node->is_parasitic_net = FALSE;
|
||||
cur_rr_node->is_in_heap = FALSE;
|
||||
|
||||
cur_rr_node->sb_num_drive_rr_nodes = 0;
|
||||
cur_rr_node->sb_drive_rr_nodes = NULL;
|
||||
cur_rr_node->sb_drive_switches = NULL;
|
||||
|
||||
cur_rr_node->pb = NULL;
|
||||
|
||||
cur_rr_node->name_mux = NULL;
|
||||
cur_rr_node->id_path = -1;
|
||||
|
||||
cur_rr_node->prev_node = -1;
|
||||
cur_rr_node->prev_edge = -1;
|
||||
cur_rr_node->net_num = -1;
|
||||
cur_rr_node->vpack_net_num = -1;
|
||||
|
||||
cur_rr_node->prev_node_in_pack = -1;
|
||||
cur_rr_node->prev_edge_in_pack = -1;
|
||||
cur_rr_node->net_num_in_pack = -1;
|
||||
|
||||
cur_rr_node->pb_graph_pin = NULL;
|
||||
cur_rr_node->tnode = NULL;
|
||||
|
||||
cur_rr_node->pack_intrinsic_cost = 0.;
|
||||
cur_rr_node->z = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Generate the number of tracks for each types of routing segments
|
||||
* w.r.t. the frequency of each of segments and channel width
|
||||
* Note that if we dertermine the number of tracks per type using
|
||||
* chan_width * segment_frequency / total_freq may cause
|
||||
* The total track num may not match the chan_width,
|
||||
* therefore, we assign tracks one by one until we meet the frequency requirement
|
||||
* In this way, we can assign the number of tracks with repect to frequency
|
||||
***********************************************************************/
|
||||
static
|
||||
std::vector<size_t> get_num_tracks_per_seg_type(const size_t chan_width,
|
||||
const std::vector<t_segment_inf> segment_inf,
|
||||
const bool use_full_seg_groups) {
|
||||
std::vector<size_t> result;
|
||||
std::vector<double> demand;
|
||||
/* Make sure a clean start */
|
||||
result.resize(segment_inf.size());
|
||||
demand.resize(segment_inf.size());
|
||||
|
||||
/* Scale factor so we can divide by any length
|
||||
* and still use integers */
|
||||
/* Get the sum of frequency */
|
||||
size_t scale = 1;
|
||||
size_t freq_sum = 0;
|
||||
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
|
||||
scale *= segment_inf[iseg].length;
|
||||
freq_sum += segment_inf[iseg].frequency;
|
||||
}
|
||||
size_t reduce = scale * freq_sum;
|
||||
|
||||
/* Init assignments to 0 and set the demand values */
|
||||
/* Get the fraction of each segment type considering the frequency:
|
||||
* num_track_per_seg = chan_width * (freq_of_seg / sum_freq)
|
||||
*/
|
||||
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
|
||||
result[iseg] = 0;
|
||||
demand[iseg] = scale * chan_width * segment_inf[iseg].frequency;
|
||||
if (true == use_full_seg_groups) {
|
||||
demand[iseg] /= segment_inf[iseg].length;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if the sum of num_tracks, matches the chan_width */
|
||||
/* Keep assigning tracks until we use them up */
|
||||
size_t assigned = 0;
|
||||
size_t size = 0;
|
||||
size_t imax = 0;
|
||||
while (assigned < chan_width) {
|
||||
/* Find current maximum demand */
|
||||
double max = 0;
|
||||
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
|
||||
if (demand[iseg] > max) {
|
||||
imax = iseg;
|
||||
}
|
||||
max = std::max(demand[iseg], max);
|
||||
}
|
||||
|
||||
/* Assign tracks to the type and reduce the types demand */
|
||||
size = (use_full_seg_groups ? segment_inf[imax].length : 1);
|
||||
demand[imax] -= reduce;
|
||||
result[imax] += size;
|
||||
assigned += size;
|
||||
}
|
||||
|
||||
/* Undo last assignment if we were closer to goal without it */
|
||||
if ((assigned - chan_width) > (size / 2)) {
|
||||
result[imax] -= size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Build details of routing tracks in a channel
|
||||
* The function will
|
||||
* 1. Assign the segments for each routing channel,
|
||||
* To be specific, for each routing track, we assign a routing segment.
|
||||
* The assignment is subject to users' specifications, such as
|
||||
* a. length of each type of segment
|
||||
* b. frequency of each type of segment.
|
||||
* c. routing channel width
|
||||
*
|
||||
* 2. The starting point of each segment in the channel will be assigned
|
||||
* For each segment group with same directionality (tracks have the same length),
|
||||
* every L track will be a starting point (where L denotes the length of segments)
|
||||
* In this case, if the number of tracks is not a multiple of L,
|
||||
* indeed we may have some <L segments. This can be considered as a side effect.
|
||||
* But still the rr_graph is tileable, which is the first concern!
|
||||
*
|
||||
* Here is a quick example of Length-4 wires in a W=12 routing channel
|
||||
* +---------------------------------------+--------------+
|
||||
* | Index | Direction | Starting Point | Ending Point |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 0 | MUX--------> | Yes | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 1 | <--------MUX | Yes | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 2 | --------> | No | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 3 | <-------- | No | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 4 | --------> | No | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 5 | <-------- | No | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 7 | -------->MUX | No | Yes |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 8 | MUX<-------- | No | Yes |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 9 | MUX--------> | Yes | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 10 | <--------MUX | Yes | No |
|
||||
* +---------------------------------------+--------------+
|
||||
* | 11 | -------->MUX | No | Yes |
|
||||
* +------------------------------------------------------+
|
||||
* | 12 | <-------- | No | No |
|
||||
* +------------------------------------------------------+
|
||||
*
|
||||
* 3. SPECIAL for fringes: TOP|RIGHT|BOTTOM|RIGHT
|
||||
* if device_side is NUM_SIDES, we assume this channel does not locate on borders
|
||||
* All segments will start and ends with no exception
|
||||
*
|
||||
* 4. IMPORTANT: we should be aware that channel width maybe different
|
||||
* in X-direction and Y-direction channels!!!
|
||||
* So we will load segment details for different channels
|
||||
***********************************************************************/
|
||||
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<t_segment_inf> 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 != actual_chan_width % 2) {
|
||||
actual_chan_width++; /* increment it to be even */
|
||||
}
|
||||
assert (0 == actual_chan_width % 2);
|
||||
|
||||
/* Reserve channel width */
|
||||
chan_node_details.reserve(chan_width);
|
||||
/* Return if zero width is forced */
|
||||
if (0 == actual_chan_width) {
|
||||
return chan_node_details;
|
||||
}
|
||||
|
||||
/* Find the number of segments required by each group */
|
||||
std::vector<size_t> num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, TRUE);
|
||||
|
||||
/* Add node to ChanNodeDetails */
|
||||
size_t cur_track = 0;
|
||||
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
|
||||
/* segment length will be set to maxium segment length if this is a longwire */
|
||||
size_t seg_len = segment_inf[iseg].length;
|
||||
if (TRUE == segment_inf[iseg].longline) {
|
||||
seg_len = max_seg_length;
|
||||
}
|
||||
for (size_t itrack = 0; itrack < num_tracks[iseg]; ++itrack) {
|
||||
bool seg_start = false;
|
||||
bool seg_end = false;
|
||||
/* Every first track of a group of Length-N wires, we set a starting point */
|
||||
if (0 == itrack % seg_len) {
|
||||
seg_start = true;
|
||||
}
|
||||
/* Every last track of a group of Length-N wires, we set an ending point */
|
||||
if (seg_len - 1 == itrack % seg_len) {
|
||||
seg_end = true;
|
||||
}
|
||||
/* Since this is a unidirectional routing architecture,
|
||||
* Add a pair of tracks, 1 INC_DIRECTION track and 1 DEC_DIRECTION track
|
||||
*/
|
||||
chan_node_details.add_track(cur_track, INC_DIRECTION, iseg, seg_len, seg_start, seg_end);
|
||||
cur_track++;
|
||||
chan_node_details.add_track(cur_track, DEC_DIRECTION, iseg, seg_len, seg_start, seg_end);
|
||||
cur_track++;
|
||||
}
|
||||
}
|
||||
/* Check if all the tracks have been satisified */
|
||||
assert (cur_track == actual_chan_width);
|
||||
|
||||
/* If this is on the border of a device, segments should start */
|
||||
switch (device_side) {
|
||||
case TOP:
|
||||
case RIGHT:
|
||||
/* INC_DIRECTION should all end */
|
||||
chan_node_details.set_tracks_end(INC_DIRECTION);
|
||||
/* DEC_DIRECTION should all start */
|
||||
chan_node_details.set_tracks_start(DEC_DIRECTION);
|
||||
break;
|
||||
case BOTTOM:
|
||||
case LEFT:
|
||||
/* INC_DIRECTION should all start */
|
||||
chan_node_details.set_tracks_start(INC_DIRECTION);
|
||||
/* DEC_DIRECTION should all end */
|
||||
chan_node_details.set_tracks_end(DEC_DIRECTION);
|
||||
break;
|
||||
case NUM_SIDES:
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) Invalid device_side!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return chan_node_details;
|
||||
}
|
||||
|
||||
/* Deteremine the side of a io grid */
|
||||
static
|
||||
enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size,
|
||||
const DeviceCoordinator& grid_coordinator) {
|
||||
/* TOP side IO of FPGA */
|
||||
if (device_size.get_y() == grid_coordinator.get_y()) {
|
||||
return BOTTOM; /* Such I/O has only Bottom side pins */
|
||||
} else if (device_size.get_x() == grid_coordinator.get_x()) { /* RIGHT side IO of FPGA */
|
||||
return LEFT; /* Such I/O has only Left side pins */
|
||||
} else if (0 == grid_coordinator.get_y()) { /* BOTTOM side IO of FPGA */
|
||||
return TOP; /* Such I/O has only Top side pins */
|
||||
} else if (0 == grid_coordinator.get_x()) { /* LEFT side IO of FPGA */
|
||||
return RIGHT; /* Such I/O has only Right side pins */
|
||||
} else {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) I/O Grid is in the center part of FPGA! Currently unsupported!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Get a list of pin_index for a grid (either OPIN or IPIN)
|
||||
* For IO_TYPE, only one side will be used, we consider one side of pins
|
||||
* For others, we consider all the sides
|
||||
***********************************************************************/
|
||||
static
|
||||
std::vector<int> 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<int> pin_list;
|
||||
/* Make sure a clear start */
|
||||
pin_list.clear();
|
||||
|
||||
for (int ipin = 0; ipin < cur_grid.type->num_pins; ++ipin) {
|
||||
int class_id = cur_grid.type->pin_class[ipin];
|
||||
if ( (1 == cur_grid.type->pinloc[pin_height][pin_side][ipin])
|
||||
&& (pin_type == cur_grid.type->class_inf[class_id].type) ) {
|
||||
pin_list.push_back(ipin);
|
||||
}
|
||||
}
|
||||
return pin_list;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Get the number of pins for a grid (either OPIN or IPIN)
|
||||
* For IO_TYPE, only one side will be used, we consider one side of pins
|
||||
* For others, we consider all the sides
|
||||
***********************************************************************/
|
||||
static
|
||||
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);
|
||||
|
||||
/* Consider capacity of the grid */
|
||||
for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) {
|
||||
/* For IO_TYPE sides */
|
||||
for (size_t side = 0; side < NUM_SIDES; ++side) {
|
||||
Side side_manager(side);
|
||||
/* skip unwanted sides */
|
||||
if ( (IO_TYPE == cur_grid.type)
|
||||
&& (side != io_side_manager.to_size_t()) ) {
|
||||
continue;
|
||||
}
|
||||
/* Get pin list */
|
||||
for (int height = 0; height < cur_grid.type->height; ++height) {
|
||||
std::vector<int> pin_list = get_grid_side_pins(cur_grid, pin_type, side_manager.get_side(), height);
|
||||
num_pins += pin_list.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num_pins;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Get the number of pins for a grid (either OPIN or IPIN)
|
||||
* For IO_TYPE, only one side will be used, we consider one side of pins
|
||||
* For others, we consider all the sides
|
||||
***********************************************************************/
|
||||
static
|
||||
size_t get_grid_num_classes(const t_grid_tile& cur_grid, const enum e_pin_type pin_type) {
|
||||
size_t num_classes = 0;
|
||||
|
||||
/* Consider capacity of the grid */
|
||||
for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) {
|
||||
for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) {
|
||||
/* Bypass unmatched pin_type */
|
||||
if (pin_type != cur_grid.type->class_inf[iclass].type) {
|
||||
continue;
|
||||
}
|
||||
num_classes++;
|
||||
}
|
||||
}
|
||||
|
||||
return num_classes;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Estimate the number of rr_nodes per category:
|
||||
* CHANX, CHANY, IPIN, OPIN, SOURCE, SINK
|
||||
|
@ -600,106 +230,34 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator
|
|||
const int wire_to_ipin_switch, const int delayless_switch) {
|
||||
Side io_side_manager(io_side);
|
||||
|
||||
/* Consider capacity of the grid */
|
||||
for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) {
|
||||
/* Walk through the height of each grid,
|
||||
* get pins and configure the rr_nodes */
|
||||
for (int height = 0; height < cur_grid.type->height; ++height) {
|
||||
/* Walk through sides */
|
||||
for (size_t side = 0; side < NUM_SIDES; ++side) {
|
||||
Side side_manager(side);
|
||||
/* skip unwanted sides */
|
||||
if ( (IO_TYPE == cur_grid.type)
|
||||
&& (side != io_side_manager.to_size_t()) ) {
|
||||
continue;
|
||||
}
|
||||
/* Find OPINs */
|
||||
/* Configure pins by pins */
|
||||
std::vector<int> opin_list = get_grid_side_pins(cur_grid, DRIVER, side_manager.get_side(), height);
|
||||
for (size_t pin = 0; pin < opin_list.size(); ++pin) {
|
||||
/* Configure the rr_node for the OPIN */
|
||||
rr_graph->rr_node[*cur_node_id].type = OPIN;
|
||||
rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x();
|
||||
rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x();
|
||||
rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y();
|
||||
rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y();
|
||||
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,
|
||||
rr_graph->rr_node[*cur_node_id].xlow,
|
||||
rr_graph->rr_node[*cur_node_id].ylow,
|
||||
rr_graph->rr_node[*cur_node_id].ptc_num);
|
||||
/* Update node counter */
|
||||
(*cur_node_id)++;
|
||||
} /* End of loading OPIN rr_nodes */
|
||||
/* Find IPINs */
|
||||
/* Configure pins by pins */
|
||||
std::vector<int> ipin_list = get_grid_side_pins(cur_grid, RECEIVER, side_manager.get_side(), height);
|
||||
for (size_t pin = 0; pin < ipin_list.size(); ++pin) {
|
||||
rr_graph->rr_node[*cur_node_id].type = IPIN;
|
||||
rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x();
|
||||
rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x();
|
||||
rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y();
|
||||
rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y();
|
||||
rr_graph->rr_node[*cur_node_id].ptc_num = ipin_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,
|
||||
rr_graph->rr_node[*cur_node_id].xlow,
|
||||
rr_graph->rr_node[*cur_node_id].ylow,
|
||||
rr_graph->rr_node[*cur_node_id].ptc_num);
|
||||
/* Update node counter */
|
||||
(*cur_node_id)++;
|
||||
} /* End of loading IPIN rr_nodes */
|
||||
} /* End of side enumeration */
|
||||
} /* End of height enumeration */
|
||||
} /* End of capacity enumeration */
|
||||
|
||||
/* Consider capacity of the grid */
|
||||
for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) {
|
||||
/* Walk through the height of each grid,
|
||||
* get pins and configure the rr_nodes */
|
||||
for (int height = 0; height < cur_grid.type->height; ++height) {
|
||||
/* Set a SOURCE or a SINK rr_node for each class */
|
||||
for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) {
|
||||
/* Set a SINK rr_node for the OPIN */
|
||||
if ( DRIVER == cur_grid.type->class_inf[iclass].type) {
|
||||
rr_graph->rr_node[*cur_node_id].type = SOURCE;
|
||||
}
|
||||
if ( RECEIVER == cur_grid.type->class_inf[iclass].type) {
|
||||
rr_graph->rr_node[*cur_node_id].type = SINK;
|
||||
}
|
||||
/* Walk through the height of each grid,
|
||||
* get pins and configure the rr_nodes */
|
||||
for (int height = 0; height < cur_grid.type->height; ++height) {
|
||||
/* Walk through sides */
|
||||
for (size_t side = 0; side < NUM_SIDES; ++side) {
|
||||
Side side_manager(side);
|
||||
/* skip unwanted sides */
|
||||
if ( (IO_TYPE == cur_grid.type)
|
||||
&& (side != io_side_manager.to_size_t()) ) {
|
||||
continue;
|
||||
}
|
||||
/* Find OPINs */
|
||||
/* Configure pins by pins */
|
||||
std::vector<int> opin_list = get_grid_side_pins(cur_grid, DRIVER, side_manager.get_side(), height);
|
||||
for (size_t pin = 0; pin < opin_list.size(); ++pin) {
|
||||
/* Configure the rr_node for the OPIN */
|
||||
rr_graph->rr_node[*cur_node_id].type = OPIN;
|
||||
rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x();
|
||||
rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x();
|
||||
rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y();
|
||||
rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y();
|
||||
rr_graph->rr_node[*cur_node_id].ptc_num = iclass;
|
||||
/* 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].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 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;
|
||||
}
|
||||
/* 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;
|
||||
/* 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,
|
||||
rr_graph->rr_node[*cur_node_id].type,
|
||||
|
@ -708,9 +266,75 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator
|
|||
rr_graph->rr_node[*cur_node_id].ptc_num);
|
||||
/* Update node counter */
|
||||
(*cur_node_id)++;
|
||||
} /* End of loading OPIN rr_nodes */
|
||||
/* Find IPINs */
|
||||
/* Configure pins by pins */
|
||||
std::vector<int> ipin_list = get_grid_side_pins(cur_grid, RECEIVER, side_manager.get_side(), height);
|
||||
for (size_t pin = 0; pin < ipin_list.size(); ++pin) {
|
||||
rr_graph->rr_node[*cur_node_id].type = IPIN;
|
||||
rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x();
|
||||
rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x();
|
||||
rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y();
|
||||
rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y();
|
||||
rr_graph->rr_node[*cur_node_id].ptc_num = ipin_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,
|
||||
rr_graph->rr_node[*cur_node_id].xlow,
|
||||
rr_graph->rr_node[*cur_node_id].ylow,
|
||||
rr_graph->rr_node[*cur_node_id].ptc_num);
|
||||
/* Update node counter */
|
||||
(*cur_node_id)++;
|
||||
} /* End of loading IPIN rr_nodes */
|
||||
} /* End of side enumeration */
|
||||
} /* End of height enumeration */
|
||||
|
||||
/* Walk through the height of each grid,
|
||||
* get pins and configure the rr_nodes */
|
||||
for (int height = 0; height < cur_grid.type->height; ++height) {
|
||||
/* Set a SOURCE or a SINK rr_node for each class */
|
||||
for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) {
|
||||
/* Set a SINK rr_node for the OPIN */
|
||||
if ( DRIVER == cur_grid.type->class_inf[iclass].type) {
|
||||
rr_graph->rr_node[*cur_node_id].type = SOURCE;
|
||||
}
|
||||
if ( RECEIVER == cur_grid.type->class_inf[iclass].type) {
|
||||
rr_graph->rr_node[*cur_node_id].type = SINK;
|
||||
}
|
||||
}
|
||||
}
|
||||
rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x();
|
||||
rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x();
|
||||
rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y();
|
||||
rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y();
|
||||
rr_graph->rr_node[*cur_node_id].ptc_num = iclass;
|
||||
/* 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,
|
||||
rr_graph->rr_node[*cur_node_id].type,
|
||||
rr_graph->rr_node[*cur_node_id].xlow,
|
||||
rr_graph->rr_node[*cur_node_id].ylow,
|
||||
rr_graph->rr_node[*cur_node_id].ptc_num);
|
||||
/* Update node counter */
|
||||
(*cur_node_id)++;
|
||||
} /* End of height enumeration */
|
||||
} /* End of pin_class enumeration */
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1117,17 +741,72 @@ void alloc_rr_graph_fast_lookup(const DeviceCoordinator& device_size,
|
|||
return;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Build the edges for all the SOURCE and SINKs nodes:
|
||||
* 1. create edges between SOURCE and OPINs
|
||||
***********************************************************************/
|
||||
static
|
||||
void build_rr_graph_edges_for_source_nodes(t_rr_graph* rr_graph,
|
||||
const std::vector< std::vector<t_grid_tile> > grids) {
|
||||
for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) {
|
||||
/* Bypass all the non OPIN nodes */
|
||||
if (OPIN != rr_graph->rr_node[inode].type) {
|
||||
continue;
|
||||
}
|
||||
/* Now, we have an OPIN node, we get the source node index */
|
||||
int xlow = rr_graph->rr_node[inode].xlow;
|
||||
int ylow = rr_graph->rr_node[inode].ylow;
|
||||
int src_node_ptc_num = get_grid_pin_class_index(grids[xlow][ylow],
|
||||
rr_graph->rr_node[inode].ptc_num);
|
||||
/* 1. create edges between SOURCE and OPINs */
|
||||
int src_node_id = get_rr_node_index(xlow, ylow,
|
||||
SOURCE, src_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, inode,
|
||||
rr_graph->rr_node[inode].driver_switch);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Build the edges for all the SINKs nodes:
|
||||
* 1. create edges between IPINs and SINKs
|
||||
***********************************************************************/
|
||||
static
|
||||
void build_rr_graph_edges_for_sink_nodes(t_rr_graph* rr_graph,
|
||||
const std::vector< std::vector<t_grid_tile> > grids) {
|
||||
for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) {
|
||||
/* Bypass all the non IPIN nodes */
|
||||
if (IPIN != rr_graph->rr_node[inode].type) {
|
||||
continue;
|
||||
}
|
||||
/* Now, we have an OPIN node, we get the source node index */
|
||||
int xlow = rr_graph->rr_node[inode].xlow;
|
||||
int ylow = rr_graph->rr_node[inode].ylow;
|
||||
int sink_node_ptc_num = get_grid_pin_class_index(grids[xlow][ylow],
|
||||
rr_graph->rr_node[inode].ptc_num);
|
||||
/* 1. create edges between IPINs and SINKs */
|
||||
int sink_node_id = get_rr_node_index(xlow, ylow,
|
||||
SINK, sink_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, inode, sink_node_id,
|
||||
rr_graph->rr_node[inode].driver_switch);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Build the edges of each rr_node tile by tile:
|
||||
* We classify rr_nodes into a general switch block (GSB) data structure
|
||||
* where we create edges to each rr_nodes in the GSB with respect to
|
||||
* Fc_in and Fc_out, switch block patterns
|
||||
* For each GSB:
|
||||
* 1. create edges between 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)
|
||||
* 1. create edges between CHANX | CHANY and IPINs (connections inside connection blocks)
|
||||
* 2. create edges between OPINs, CHANX and CHANY (connections inside switch blocks)
|
||||
* 3. create edges between OPINs and IPINs (direct-connections)
|
||||
***********************************************************************/
|
||||
static
|
||||
void build_rr_graph_edges(t_rr_graph* rr_graph,
|
||||
|
@ -1138,6 +817,10 @@ void build_rr_graph_edges(t_rr_graph* rr_graph,
|
|||
int** Fc_in, int** Fc_out,
|
||||
const enum e_switch_block_type sb_type, const int Fs) {
|
||||
|
||||
/* Create edges for SOURCE and SINK nodes for a tileable rr_graph */
|
||||
build_rr_graph_edges_for_source_nodes(rr_graph, grids);
|
||||
build_rr_graph_edges_for_sink_nodes(rr_graph, grids);
|
||||
|
||||
DeviceCoordinator gsb_range(device_size.get_x() - 2, device_size.get_y() - 2);
|
||||
|
||||
/* Go Switch Block by Switch Block */
|
||||
|
@ -1162,7 +845,7 @@ void build_rr_graph_edges(t_rr_graph* rr_graph,
|
|||
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, grids, &rr_gsb,
|
||||
build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb,
|
||||
track2ipin_map, opin2track_map,
|
||||
sb_conn);
|
||||
/* Finish this GSB, go to the next*/
|
||||
|
@ -1251,7 +934,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
|
|||
INP const int num_seg_types,
|
||||
INP const t_segment_inf * segment_inf,
|
||||
INP const int num_switches, INP const int delayless_switch,
|
||||
INP const int global_route_switch,
|
||||
INP const t_timing_inf timing_inf,
|
||||
INP const int wire_to_ipin_switch,
|
||||
INP const enum e_base_cost_type base_cost_type,
|
||||
|
@ -1317,9 +999,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
|
|||
tileable_rr_graph_init_rr_node(&(rr_graph.rr_node[i]));
|
||||
}
|
||||
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"%d RR graph nodes allocated.\n", rr_graph.num_rr_nodes);
|
||||
|
||||
/************************************************************************
|
||||
* 4. Initialize the basic information of rr_nodes:
|
||||
* coordinators: xlow, ylow, xhigh, yhigh,
|
||||
|
@ -1331,9 +1010,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
|
|||
load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs,
|
||||
wire_to_ipin_switch, delayless_switch);
|
||||
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Built node basic information and fast-look.\n");
|
||||
|
||||
/************************************************************************
|
||||
* 5.1 Create the connectivity of OPINs
|
||||
* a. Evenly assign connections to OPINs to routing tracks
|
||||
|
@ -1369,7 +1045,6 @@ void build_tileable_unidir_rr_graph(INP const 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,
|
||||
|
@ -1415,9 +1090,8 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
|
|||
"Create a tileable RR graph with %d nodes\n",
|
||||
num_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);
|
||||
check_rr_graph(GRAPH_UNIDIR_TILEABLE, L_nx, L_ny,
|
||||
num_switches, Fc_in);
|
||||
|
||||
/* Print useful information on screen */
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
|
@ -1,16 +1,10 @@
|
|||
#ifndef RR_GRAPH_TILEABLE_BUILDER_H
|
||||
#define RR_GRAPH_TILEABLE_BUILDER_H
|
||||
#ifndef TILEABLE_RR_GRAPH_BUILDER_H
|
||||
#define TILEABLE_RR_GRAPH_BUILDER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#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<t_segment_inf> 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 struct s_grid_tile **L_grid, INP const int chan_width,
|
||||
|
@ -18,7 +12,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types,
|
|||
INP const int num_seg_types,
|
||||
INP const t_segment_inf * segment_inf,
|
||||
INP const int num_switches, INP const int delayless_switch,
|
||||
const int global_route_switch,
|
||||
INP const t_timing_inf timing_inf, INP const int wire_to_ipin_switch,
|
||||
INP const enum e_base_cost_type base_cost_type,
|
||||
INP const t_direct_inf *directs,
|
|
@ -23,7 +23,7 @@
|
|||
***********************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Filename: rr_graph_tileable_gsb.cpp
|
||||
* Filename: tileable_rr_graph_gsb.cpp
|
||||
* Created by: Xifan Tang
|
||||
* Change history:
|
||||
* +-------------------------------------+
|
||||
|
@ -48,8 +48,9 @@
|
|||
#include "rr_graph_util.h"
|
||||
#include "rr_graph2.h"
|
||||
|
||||
#include "rr_graph_tileable_gsb.h"
|
||||
#include "rr_graph_tileable_builder.h"
|
||||
#include "rr_graph_builder_utils.h"
|
||||
#include "tileable_chan_details_builder.h"
|
||||
#include "tileable_rr_graph_gsb.h"
|
||||
|
||||
#include "fpga_x2p_backannotate_utils.h"
|
||||
|
||||
|
@ -885,67 +886,13 @@ RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range,
|
|||
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;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Get the class index of a grid pin
|
||||
***********************************************************************/
|
||||
static
|
||||
int get_grid_pin_class_index(const t_grid_tile& cur_grid,
|
||||
const int pin_index) {
|
||||
/* check */
|
||||
assert ( pin_index < cur_grid.type->num_pins);
|
||||
return cur_grid.type->pin_class[pin_index];
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* 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)
|
||||
* 1. create edges between CHANX | CHANY and IPINs (connections inside connection blocks)
|
||||
* 2. create edges between OPINs, CHANX and CHANY (connections inside switch blocks)
|
||||
* 3. create edges between OPINs and IPINs (direct-connections)
|
||||
***********************************************************************/
|
||||
void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph,
|
||||
const std::vector< std::vector<t_grid_tile> > grids,
|
||||
const RRGSB* rr_gsb,
|
||||
const t_track2pin_map track2ipin_map,
|
||||
const t_pin2track_map opin2track_map,
|
||||
|
@ -961,15 +908,8 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph,
|
|||
/* 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);
|
||||
int src_node_ptc_num = get_grid_pin_class_index(grids[opin_node->xlow][opin_node->ylow], opin_node->ptc_num);
|
||||
/* 1. create edges between SOURCE and OPINs */
|
||||
int src_node_id = get_rr_node_index(opin_node->xlow, opin_node->ylow,
|
||||
SOURCE, src_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 */
|
||||
|
||||
/* 1. 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];
|
||||
|
@ -979,25 +919,13 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph,
|
|||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
int sink_node_ptc_num = get_grid_pin_class_index(grids[ipin_node->xlow][ipin_node->ylow], ipin_node->ptc_num);
|
||||
/* 3. create edges between IPINs and SINKs */
|
||||
int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow,
|
||||
SINK, sink_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 TRACKs to IPINs, we only care LEFT and TOP sides
|
||||
* Skip RIGHT and BOTTOM for the ipin2track_map since they should be handled in other GSBs
|
||||
*/
|
||||
if ( (side_manager.get_side() == rr_gsb->get_cb_chan_side(CHANX))
|
||||
|| (side_manager.get_side() == rr_gsb->get_cb_chan_side(CHANY)) ) {
|
||||
/* 4. create edges between CHANX|CHANY and IPINs, using ipin2track_map */
|
||||
/* 2. create edges between CHANX|CHANY and IPINs, using ipin2track_map */
|
||||
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);
|
||||
int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size();
|
||||
|
@ -1010,7 +938,7 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph,
|
|||
}
|
||||
}
|
||||
|
||||
/* 5. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */
|
||||
/* 3. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */
|
||||
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);
|
||||
int num_edges = track2track_map[side_manager.to_size_t()][inode].size();
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef RR_GRAPH_TILEABLE_GSB_H
|
||||
#define RR_GRAPH_TILEABLE_GSB_H
|
||||
#ifndef TILEABLE_RR_GRAPH_GSB_H
|
||||
#define TILEABLE_RR_GRAPH_GSB_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -32,7 +32,6 @@ RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range,
|
|||
t_rr_graph* rr_graph);
|
||||
|
||||
void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph,
|
||||
const std::vector< std::vector<t_grid_tile> > grids,
|
||||
const RRGSB* rr_gsb,
|
||||
const t_track2pin_map track2ipin_map,
|
||||
const t_pin2track_map opin2track_map,
|
|
@ -22,13 +22,26 @@ static boolean rr_node_is_global_clb_ipin(int inode);
|
|||
static void check_pass_transistors(int from_node);
|
||||
|
||||
/************************ Subroutine definitions ****************************/
|
||||
/****************************************************************************
|
||||
* Print detailed information of a node to ease debugging
|
||||
****************************************************************************/
|
||||
static
|
||||
void print_rr_node_details(t_rr_node* cur_rr_node) {
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"\tNode %d details: type=%s, (xlow,ylow)=(%d,%d)->(xhigh,yhigh)=(%d,%d), ptc_num=%d\n",
|
||||
cur_rr_node - rr_node,
|
||||
rr_node_typename[cur_rr_node->type],
|
||||
cur_rr_node->xlow, cur_rr_node->ylow,
|
||||
cur_rr_node->xhigh, cur_rr_node->yhigh,
|
||||
cur_rr_node->ptc_num);
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
void check_rr_graph(INP const t_graph_type graph_type,
|
||||
INP const int L_nx, INP const int L_ny,
|
||||
INP const int num_switches,
|
||||
int **Fc_in) {
|
||||
|
||||
int *num_edges_from_current_to_node; /* [0..num_rr_nodes-1] */
|
||||
int *total_edges_to_node; /* [0..num_rr_nodes-1] */
|
||||
|
@ -63,7 +76,9 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types,
|
|||
to_node = rr_node[inode].edges[iedge];
|
||||
|
||||
if (to_node < 0 || to_node >= num_rr_nodes) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has an edge %d.\n", inode, to_node);
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has an edge %d.\n", inode, to_node);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "\tEdge is out of range.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -75,6 +90,7 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types,
|
|||
|
||||
if (switch_type < 0 || switch_type >= num_switches) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has a switch type %d.\n", inode, switch_type);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "\tSwitch type is out of range.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -96,6 +112,8 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types,
|
|||
|| (rr_type != CHANX && rr_type != CHANY)) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d connects to node %d %d times.\n",
|
||||
inode, to_node, num_edges_from_current_to_node[to_node]);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
print_rr_node_details(&rr_node[to_node]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -106,6 +124,8 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types,
|
|||
|| switch_types_from_current_to_node[to_node] != BUF_AND_PTRANS_FLAG) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d connects to node %d %d times.\n",
|
||||
inode, to_node, num_edges_from_current_to_node[to_node]);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
print_rr_node_details(&rr_node[to_node]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -157,10 +177,12 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types,
|
|||
|
||||
if (!is_chain && !is_fringe && !is_wire) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has no fanin.\n", inode);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
} else if (!is_chain && !is_fringe_warning_sent) {
|
||||
vpr_printf(TIO_MESSAGE_WARNING, "in check_rr_graph: fringe node %d has no fanin.\n", inode);
|
||||
vpr_printf(TIO_MESSAGE_WARNING, "\tThis is possible on the fringe for low Fc_out, N, and certain Lengths\n");
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
is_fringe_warning_sent = TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -170,6 +192,7 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types,
|
|||
if (total_edges_to_node[inode] != 0) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: SOURCE node %d has a fanin of %d, expected 0.\n",
|
||||
inode, total_edges_to_node[inode]);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -224,18 +247,21 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
if (xlow > xhigh || ylow > yhigh) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: rr endpoints are (%d,%d) and (%d,%d).\n",
|
||||
xlow, ylow, xhigh, yhigh);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (xlow < 0 || xhigh > nx + 1 || ylow < 0 || yhigh > ny + 1) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: rr endpoints (%d,%d) and (%d,%d) are out of range.\n",
|
||||
xlow, ylow, xhigh, yhigh);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ptc_num < 0) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
|
||||
inode, rr_type, ptc_num);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -253,11 +279,13 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
if (type == NULL) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d (type %d) is at an illegal clb location (%d, %d).\n",
|
||||
inode, rr_type, xlow, ylow);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
if (xlow != xhigh || ylow != (yhigh - type->height + 1)) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d (type %d) has endpoints (%d,%d) and (%d,%d)\n",
|
||||
inode, rr_type, xlow, ylow, xhigh, yhigh);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -276,11 +304,13 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
/* end */
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: CHANX out of range for endpoints (%d,%d) and (%d,%d)\n",
|
||||
xlow, ylow, xhigh, yhigh);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
if (route_type == GLOBAL && xlow != xhigh) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d spans multiple channel segments (not allowed for global routing).\n",
|
||||
inode);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -299,11 +329,13 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
/* end */
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "Error in check_node: CHANY out of range for endpoints (%d,%d) and (%d,%d)\n",
|
||||
xlow, ylow, xhigh, yhigh);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
if (route_type == GLOBAL && ylow != yhigh) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d spans multiple channel segments (not allowed for global routing).\n",
|
||||
inode);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -323,11 +355,13 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
|| type->class_inf[ptc_num].type != DRIVER) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
|
||||
inode, rr_type, ptc_num);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
if (type->class_inf[ptc_num].num_pins != capacity) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a capacity of %d.\n",
|
||||
inode, rr_type, capacity);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -338,11 +372,13 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
|| type->class_inf[ptc_num].type != RECEIVER) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
|
||||
inode, rr_type, ptc_num);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
if (type->class_inf[ptc_num].num_pins != capacity) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
|
||||
inode, rr_type, capacity);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -353,12 +389,14 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
|| type->class_inf[type->pin_class[ptc_num]].type != DRIVER) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
|
||||
inode, rr_type, ptc_num);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (capacity != 1) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
|
||||
inode, rr_type, capacity);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -368,11 +406,13 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
|| type->class_inf[type->pin_class[ptc_num]].type != RECEIVER) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
|
||||
inode, rr_type, ptc_num);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
if (capacity != 1) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
|
||||
inode, rr_type, capacity);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -389,12 +429,14 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
if (ptc_num >= nodes_per_chan) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a ptc_num of %d.\n",
|
||||
inode, rr_type, ptc_num);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (capacity != tracks_per_node) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
|
||||
inode, rr_type, capacity);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -411,12 +453,14 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
if (ptc_num >= nodes_per_chan) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a ptc_num of %d.\n",
|
||||
inode, rr_type, ptc_num);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (capacity != tracks_per_node) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
|
||||
inode, rr_type, capacity);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
@ -436,6 +480,7 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
* If such a node was ever used in a final routing (not just in an rr_graph), other *
|
||||
* error checks in check_routing will catch it. */
|
||||
vpr_printf(TIO_MESSAGE_WARNING, "in check_node: node %d has no edges.\n", inode);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -443,6 +488,7 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
if (num_edges != 0) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d is a sink, but has %d edges.\n",
|
||||
inode, num_edges);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -456,6 +502,7 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
if (C < 0. || R < 0.) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d of type %d has R = %g and C = %g.\n",
|
||||
inode, rr_type, R, C);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -464,6 +511,7 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
if (C != 0. || R != 0.) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d of type %d has R = %g and C = %g.\n",
|
||||
inode, rr_type, R, C);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -472,6 +520,7 @@ void check_node(int inode, enum e_route_type route_type) {
|
|||
if (cost_index < 0 || cost_index >= num_rr_indexed_data) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d cost index (%d) is out of range.\n",
|
||||
inode, cost_index);
|
||||
print_rr_node_details(&rr_node[inode]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -531,6 +580,8 @@ static void check_pass_transistors(int from_node) {
|
|||
vpr_printf(TIO_MESSAGE_ERROR, "connection from node %d to node %d uses a pass transistor (switch type %d)\n",
|
||||
from_node, to_node, from_switch_type);
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "but there is no corresponding pass transistor edge in the other direction.\n");
|
||||
print_rr_node_details(&rr_node[from_node]);
|
||||
print_rr_node_details(&rr_node[to_node]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,9 @@
|
|||
#define CHECK_RR_GRAPH_H
|
||||
|
||||
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 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);
|
||||
INP const int L_nx, INP const int L_ny,
|
||||
INP const int num_switches,
|
||||
int **Fc_in);
|
||||
|
||||
void check_node(int inode, enum e_route_type route_type);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "read_xml_arch_file.h"
|
||||
#include "ReadOptions.h"
|
||||
|
||||
#include "rr_graph_tileable_builder.h"
|
||||
#include "tileable_rr_graph_builder.h"
|
||||
|
||||
/* Xifan TANG: SWSEG SUPPORT */
|
||||
#include "rr_graph_swseg.h"
|
||||
|
@ -226,7 +226,7 @@ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types,
|
|||
L_nx, L_ny, L_grid,
|
||||
chan_width,
|
||||
sb_type, Fs, num_seg_types, segment_inf,
|
||||
num_switches, global_route_switch, delayless_switch,
|
||||
num_switches, delayless_switch,
|
||||
timing_inf, wire_to_ipin_switch,
|
||||
base_cost_type, directs, num_directs, ignore_Fc_0, Warnings);
|
||||
} else {
|
||||
|
@ -523,9 +523,8 @@ void build_classic_rr_graph(INP t_graph_type graph_type, INP int L_num_types,
|
|||
} else
|
||||
;
|
||||
|
||||
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, Fc_in, Fc_out);
|
||||
check_rr_graph(graph_type, L_nx, L_ny,
|
||||
num_switches, Fc_in);
|
||||
|
||||
/* Free all temp structs */
|
||||
if (seg_details) {
|
||||
|
|
Loading…
Reference in New Issue