developing tileable routing track arrangement
This commit is contained in:
parent
4d2a3680be
commit
a33627606e
|
@ -0,0 +1,268 @@
|
|||
/**********************************************************
|
||||
* 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: chan_node_details.cpp
|
||||
* Created by: Xifan Tang
|
||||
* Change history:
|
||||
* +-------------------------------------+
|
||||
* | Date | Author | Notes
|
||||
* +-------------------------------------+
|
||||
* | 2019/06/14 | Xifan Tang | Created
|
||||
* +-------------------------------------+
|
||||
***********************************************************************/
|
||||
/************************************************************************
|
||||
* This file contains member functions for class ChanNodeDetails
|
||||
***********************************************************************/
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include "chan_node_details.h"
|
||||
|
||||
/************************************************************************
|
||||
* Constructors
|
||||
***********************************************************************/
|
||||
ChanNodeDetails::ChanNodeDetails(const ChanNodeDetails& src) {
|
||||
/* duplicate */
|
||||
size_t chan_width = src.get_chan_width();
|
||||
this->reserve(chan_width);
|
||||
for (size_t itrack = 0; itrack < chan_width; ++itrack) {
|
||||
track_node_ids_.push_back(src.get_track_node_id(itrack));
|
||||
track_direction_.push_back(src.get_track_direction(itrack));
|
||||
seg_length_.push_back(src.get_track_segment_length(itrack));
|
||||
track_start_.push_back(src.is_track_start(itrack));
|
||||
track_end_.push_back(src.is_track_end(itrack));
|
||||
}
|
||||
}
|
||||
|
||||
ChanNodeDetails::ChanNodeDetails() {
|
||||
this->clear();
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Accessors
|
||||
***********************************************************************/
|
||||
size_t ChanNodeDetails::get_chan_width() const {
|
||||
assert(validate_chan_width());
|
||||
return track_node_ids_.size();
|
||||
}
|
||||
|
||||
size_t ChanNodeDetails::get_track_node_id(size_t track_id) const {
|
||||
assert(validate_track_id(track_id));
|
||||
return track_node_ids_[track_id];
|
||||
}
|
||||
|
||||
e_direction ChanNodeDetails::get_track_direction(size_t track_id) const {
|
||||
assert(validate_track_id(track_id));
|
||||
return track_direction_[track_id];
|
||||
}
|
||||
|
||||
size_t ChanNodeDetails::get_track_segment_length(size_t track_id) const {
|
||||
assert(validate_track_id(track_id));
|
||||
return seg_length_[track_id];
|
||||
}
|
||||
|
||||
bool ChanNodeDetails::is_track_start(size_t track_id) const {
|
||||
assert(validate_track_id(track_id));
|
||||
return track_start_[track_id];
|
||||
}
|
||||
|
||||
bool ChanNodeDetails::is_track_end(size_t track_id) const {
|
||||
assert(validate_track_id(track_id));
|
||||
return track_end_[track_id];
|
||||
}
|
||||
|
||||
/* Track_id is the starting point of group (whose is_start should be true)
|
||||
* This function will try to find the track_ids with the same directionality as track_id and seg_length
|
||||
* A group size is the number of such nodes between the starting points (include the 1st starting point)
|
||||
*/
|
||||
std::vector<size_t> ChanNodeDetails::get_seg_group(size_t track_id) const {
|
||||
assert(validate_chan_width());
|
||||
assert(validate_track_id(track_id));
|
||||
assert(is_track_start(track_id));
|
||||
|
||||
std::vector<size_t> group;
|
||||
/* Make sure a clean start */
|
||||
group.clear();
|
||||
|
||||
/* track_id is the first element */
|
||||
group.push_back(track_id);
|
||||
|
||||
for (size_t itrack = track_id; itrack < get_chan_width(); ++itrack) {
|
||||
if ( (get_track_direction(itrack) == get_track_direction(track_id) )
|
||||
&& (get_track_segment_length(itrack) == get_track_segment_length(track_id)) ) {
|
||||
if ( (false == is_track_start(itrack))
|
||||
|| ( (true == is_track_start(itrack)) && (itrack == track_id)) ) {
|
||||
group.push_back(itrack);
|
||||
continue;
|
||||
}
|
||||
/* Stop if this another starting point */
|
||||
if (true == is_track_start(itrack)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
/* Get a list of track_ids with the given list of track indices */
|
||||
std::vector<size_t> ChanNodeDetails::get_seg_group_node_id(std::vector<size_t> seg_group) const {
|
||||
std::vector<size_t> group;
|
||||
/* Make sure a clean start */
|
||||
group.clear();
|
||||
|
||||
for (size_t id = 0; id < seg_group.size(); ++id) {
|
||||
assert(validate_track_id(seg_group[id]));
|
||||
group.push_back(get_track_node_id(seg_group[id]));
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
/* Get the number of tracks that starts in this routing channel */
|
||||
size_t ChanNodeDetails::get_num_starting_tracks() const {
|
||||
size_t counter = 0;
|
||||
for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) {
|
||||
if (false == is_track_start(itrack)) {
|
||||
continue;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
/* Get the number of tracks that ends in this routing channel */
|
||||
size_t ChanNodeDetails::get_num_ending_tracks() const {
|
||||
size_t counter = 0;
|
||||
for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) {
|
||||
if (false == is_track_end(itrack)) {
|
||||
continue;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Mutators
|
||||
***********************************************************************/
|
||||
/* Reserve the capacitcy of vectors */
|
||||
void ChanNodeDetails::reserve(size_t chan_width) {
|
||||
track_node_ids_.reserve(chan_width);
|
||||
track_direction_.reserve(chan_width);
|
||||
seg_length_.reserve(chan_width);
|
||||
track_start_.reserve(chan_width);
|
||||
track_end_.reserve(chan_width);
|
||||
}
|
||||
|
||||
/* Add a track to the channel */
|
||||
void ChanNodeDetails::add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end) {
|
||||
track_node_ids_.push_back(track_node_id);
|
||||
track_direction_.push_back(track_direction);
|
||||
seg_length_.push_back(seg_length);
|
||||
track_start_.push_back(is_start);
|
||||
track_end_.push_back(is_end);
|
||||
}
|
||||
|
||||
/* Set tracks with a given direction to start */
|
||||
void ChanNodeDetails::set_tracks_start(e_direction track_direction) {
|
||||
for (size_t inode = 0; inode < get_chan_width(); ++inode) {
|
||||
/* Bypass non-match tracks */
|
||||
if (track_direction != get_track_direction(inode)) {
|
||||
}
|
||||
track_start_[inode] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set tracks with a given direction to end */
|
||||
void ChanNodeDetails::set_tracks_end(e_direction track_direction) {
|
||||
for (size_t inode = 0; inode < get_chan_width(); ++inode) {
|
||||
/* Bypass non-match tracks */
|
||||
if (track_direction != get_track_direction(inode)) {
|
||||
}
|
||||
track_end_[inode] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* rotate the track_node_id by an offset */
|
||||
void ChanNodeDetails::rotate_track_node_id(size_t offset, bool counter_rotate) {
|
||||
/* Rotate the node_ids by groups
|
||||
* A group begins from a track_start and ends before another track_start
|
||||
*/
|
||||
assert(validate_chan_width());
|
||||
for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) {
|
||||
/* Bypass non-start segment */
|
||||
if (false == is_track_start(itrack) ) {
|
||||
continue;
|
||||
}
|
||||
/* Find the group nodes */
|
||||
std::vector<size_t> track_group = get_seg_group(itrack);
|
||||
/* Build a vector of the node ids of the tracks */
|
||||
std::vector<size_t> track_group_node_id = get_seg_group_node_id(track_group);
|
||||
/* Rotate or Counter rotate */
|
||||
if (true == counter_rotate) {
|
||||
std::rotate(track_group_node_id.begin(), track_group_node_id.end() - offset, track_group_node_id.end());
|
||||
} else {
|
||||
std::rotate(track_group_node_id.begin(), track_group_node_id.begin() + offset, track_group_node_id.end());
|
||||
}
|
||||
/* Update the node_ids */
|
||||
for (size_t inode = 0; inode < track_group.size(); ++inode) {
|
||||
track_node_ids_[track_group[inode]] = track_group_node_id[inode];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void ChanNodeDetails::clear() {
|
||||
track_node_ids_.clear();
|
||||
track_direction_.clear();
|
||||
seg_length_.clear();
|
||||
track_start_.clear();
|
||||
track_end_.clear();
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Validators
|
||||
***********************************************************************/
|
||||
bool ChanNodeDetails::validate_chan_width() const {
|
||||
size_t chan_width = track_node_ids_.size();
|
||||
if ( (chan_width == track_direction_.size())
|
||||
&&(chan_width == seg_length_.size())
|
||||
&&(chan_width == track_start_.size())
|
||||
&&(chan_width == track_end_.size()) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChanNodeDetails::validate_track_id(size_t track_id) const {
|
||||
if ( (track_id < track_node_ids_.size())
|
||||
&& (track_id < track_direction_.size())
|
||||
&& (track_id < seg_length_.size())
|
||||
&& (track_id < track_start_.size())
|
||||
&& (track_id < track_end_.size()) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/**********************************************************
|
||||
* 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: chan_node_details.h
|
||||
* Created by: Xifan Tang
|
||||
* Change history:
|
||||
* +-------------------------------------+
|
||||
* | Date | Author | Notes
|
||||
* +-------------------------------------+
|
||||
* | 2019/06/11 | Xifan Tang | Created
|
||||
* +-------------------------------------+
|
||||
***********************************************************************/
|
||||
/************************************************************************
|
||||
* This file contains a class to model the details of routing node
|
||||
* in a channel:
|
||||
* 1. segment information: length, frequency etc.
|
||||
* 2. starting point of segment
|
||||
* 3. ending point of segment
|
||||
* 4. potentail track_id(ptc_num) of each segment
|
||||
***********************************************************************/
|
||||
|
||||
/* IMPORTANT:
|
||||
* The following preprocessing flags are added to
|
||||
* avoid compilation error when this headers are included in more than 1 times
|
||||
*/
|
||||
#ifndef CHAN_NODE_DETAILS_H
|
||||
#define CHAN_NODE_DETAILS_H
|
||||
|
||||
/*
|
||||
* Notes in include header files in a head file
|
||||
* Only include the neccessary header files
|
||||
* that is required by the data types in the function/class declarations!
|
||||
*/
|
||||
/* Header files should be included in a sequence */
|
||||
/* Standard header files required go first */
|
||||
#include <vector>
|
||||
#include "vpr_types.h"
|
||||
|
||||
/************************************************************************
|
||||
* ChanNodeDetails records segment length, directionality and starting of routing tracks
|
||||
* +---------------------------------+
|
||||
* | Index | Direction | Start Point |
|
||||
* +---------------------------------+
|
||||
* | 0 | --------> | Yes |
|
||||
* +---------------------------------+
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
class ChanNodeDetails {
|
||||
public : /* Constructor */
|
||||
ChanNodeDetails(const ChanNodeDetails&); /* Duplication */
|
||||
ChanNodeDetails(); /* Initilization */
|
||||
public: /* Accessors */
|
||||
size_t get_chan_width() const;
|
||||
size_t get_track_node_id(size_t track_id) const;
|
||||
e_direction get_track_direction(size_t track_id) const;
|
||||
size_t get_track_segment_length(size_t track_id) const;
|
||||
bool is_track_start(size_t track_id) const;
|
||||
bool is_track_end(size_t track_id) const;
|
||||
std::vector<size_t> get_seg_group(size_t track_id) const;
|
||||
std::vector<size_t> get_seg_group_node_id(std::vector<size_t> seg_group) const;
|
||||
size_t get_num_starting_tracks() const;
|
||||
size_t get_num_ending_tracks() const;
|
||||
public: /* Mutators */
|
||||
void reserve(size_t chan_width); /* Reserve the capacitcy of vectors */
|
||||
void add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end);
|
||||
void set_tracks_start(e_direction track_direction);
|
||||
void set_tracks_end(e_direction track_direction);
|
||||
void rotate_track_node_id(size_t offset, bool counter_rotate); /* rotate the track_node_id by an offset */
|
||||
void clear();
|
||||
private: /* validators */
|
||||
bool validate_chan_width() const;
|
||||
bool validate_track_id(size_t track_id) const;
|
||||
private: /* Internal data */
|
||||
std::vector<size_t> track_node_ids_; /* indices of each track */
|
||||
std::vector<e_direction> track_direction_; /* direction of each track */
|
||||
std::vector<size_t> seg_length_; /* Length of each segment */
|
||||
std::vector<bool> track_start_; /* flag to identify if this is the starting point of the track */
|
||||
std::vector<bool> track_end_; /* flag to identify if this is the ending point of the track */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -55,11 +55,213 @@
|
|||
#include "fpga_x2p_types.h"
|
||||
#include "rr_graph_tileable_builder.h"
|
||||
|
||||
#include "chan_node_details.h"
|
||||
|
||||
/************************************************************************
|
||||
* Local function in the file
|
||||
***********************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* 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(size_t chan_width,
|
||||
std::vector<t_segment_inf> segment_inf,
|
||||
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 | Start Point |
|
||||
* +---------------------------------+
|
||||
* | 0 | --------> | Yes |
|
||||
* +---------------------------------+
|
||||
* | 1 | <-------- | Yes |
|
||||
* +---------------------------------+
|
||||
* | 2 | --------> | No |
|
||||
* +---------------------------------+
|
||||
* | 3 | <-------- | No |
|
||||
* +---------------------------------+
|
||||
* | 4 | --------> | No |
|
||||
* +---------------------------------+
|
||||
* | 5 | <-------- | No |
|
||||
* +---------------------------------+
|
||||
* | 7 | --------> | No |
|
||||
* +---------------------------------+
|
||||
* | 8 | <-------- | No |
|
||||
* +---------------------------------+
|
||||
* | 9 | --------> | Yes |
|
||||
* +---------------------------------+
|
||||
* | 10 | <-------- | Yes |
|
||||
* +---------------------------------+
|
||||
* | 11 | --------> | No |
|
||||
* +---------------------------------+
|
||||
* | 12 | <-------- | 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
|
||||
***********************************************************************/
|
||||
static
|
||||
ChanNodeDetails build_unidir_chan_node_details(size_t chan_width, size_t max_seg_length,
|
||||
enum e_side device_side,
|
||||
std::vector<t_segment_inf> segment_inf) {
|
||||
ChanNodeDetails chan_node_details;
|
||||
/* Correct the chan_width: it should be an even number */
|
||||
if (0 != chan_width % 2) {
|
||||
chan_width++; /* increment it to be even */
|
||||
}
|
||||
assert (0 == chan_width % 2);
|
||||
|
||||
/* Reserve channel width */
|
||||
chan_node_details.reserve(chan_width);
|
||||
/* Return if zero width is forced */
|
||||
if (0 == 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(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;
|
||||
/* Every length of wire, we set a starting point */
|
||||
if (0 == itrack % seg_len) {
|
||||
seg_start = 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, seg_len, seg_start, false);
|
||||
cur_track++;
|
||||
chan_node_details.add_track(cur_track, DEC_DIRECTION, seg_len, seg_start, false);
|
||||
cur_track++;
|
||||
}
|
||||
}
|
||||
/* Check if all the tracks have been satisified */
|
||||
assert (cur_track == 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;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Estimate the number of rr_nodes per category:
|
||||
* CHANX, CHANY, IPIN, OPIN, SOURCE, SINK
|
||||
|
@ -122,9 +324,9 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
|||
INP t_timing_inf timing_inf, INP int wire_to_ipin_switch,
|
||||
INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs,
|
||||
INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings,
|
||||
/*Xifan TANG: Switch Segment Pattern Support*/
|
||||
INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns,
|
||||
INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) {
|
||||
/*Xifan TANG: Switch Segment Pattern Support*/
|
||||
INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns,
|
||||
INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) {
|
||||
/* Create an empty graph */
|
||||
t_rr_graph rr_graph;
|
||||
rr_graph.rr_node_indices = NULL;
|
||||
|
@ -141,6 +343,46 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
|||
* a. length of each type of segment
|
||||
* b. frequency of each type of segment.
|
||||
* c. routing channel width
|
||||
*
|
||||
* 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 | Start Point |
|
||||
* +---------------------------------+
|
||||
* | 0 | --------> | Yes |
|
||||
* +---------------------------------+
|
||||
* | 1 | <-------- | Yes |
|
||||
* +---------------------------------+
|
||||
* | 2 | --------> | No |
|
||||
* +---------------------------------+
|
||||
* | 3 | <-------- | No |
|
||||
* +---------------------------------+
|
||||
* | 4 | --------> | No |
|
||||
* +---------------------------------+
|
||||
* | 5 | <-------- | No |
|
||||
* +---------------------------------+
|
||||
* | 7 | --------> | No |
|
||||
* +---------------------------------+
|
||||
* | 8 | <-------- | No |
|
||||
* +---------------------------------+
|
||||
* | 9 | --------> | Yes |
|
||||
* +---------------------------------+
|
||||
* | 10 | <-------- | Yes |
|
||||
* +---------------------------------+
|
||||
* | 11 | --------> | No |
|
||||
* +---------------------------------+
|
||||
* | 12 | <-------- | No |
|
||||
* +---------------------------------+
|
||||
*
|
||||
* SPECIAL for fringes:
|
||||
* All segments will start and ends with no exception
|
||||
*
|
||||
* 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
|
||||
|
@ -148,11 +390,15 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
|||
/* Check the channel width */
|
||||
int nodes_per_chan = chan_width;
|
||||
assert(chan_width > 0);
|
||||
t_seg_details *seg_details = NULL;
|
||||
seg_details = alloc_and_load_seg_details(&nodes_per_chan,
|
||||
std::max(L_nx, L_ny),
|
||||
num_seg_types, segment_inf,
|
||||
TRUE, FALSE, UNI_DIRECTIONAL);
|
||||
|
||||
/* Create a vector of segment_inf */
|
||||
std::vector<t_segment_inf> segment_infs;
|
||||
for (int iseg = 0; iseg < num_seg_types; ++iseg) {
|
||||
segment_infs.push_back(segment_inf[iseg]);
|
||||
}
|
||||
|
||||
ChanNodeDetails chanx_details = build_unidir_chan_node_details(nodes_per_chan, L_nx, NUM_SIDES, segment_infs);
|
||||
ChanNodeDetails chany_details = build_unidir_chan_node_details(nodes_per_chan, L_ny, NUM_SIDES, segment_infs);
|
||||
|
||||
/* Predict the track index of each channel,
|
||||
* The track index, also called ptc_num of each CHANX and CHANY rr_node
|
||||
|
@ -204,6 +450,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
|||
* c. handle direct-connections
|
||||
***********************************************************************/
|
||||
/* Alloc node lookups, count nodes, alloc rr nodes */
|
||||
/*
|
||||
rr_graph.num_rr_nodes = 0;
|
||||
rr_graph.rr_node_indices = alloc_and_load_rr_node_indices(nodes_per_chan, L_nx, L_ny,
|
||||
&(rr_graph.num_rr_nodes), seg_details);
|
||||
|
@ -211,6 +458,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
|||
memset(rr_node, 0, sizeof(t_rr_node) * rr_graph.num_rr_nodes);
|
||||
boolean* L_rr_edge_done = (boolean *) my_malloc(sizeof(boolean) * rr_graph.num_rr_nodes);
|
||||
memset(L_rr_edge_done, 0, sizeof(boolean) * rr_graph.num_rr_nodes);
|
||||
*/
|
||||
|
||||
/* handle direct-connections */
|
||||
t_clb_to_clb_directs* clb_to_clb_directs = NULL;
|
||||
|
|
Loading…
Reference in New Issue