adapt tileable routing channel detail builder
This commit is contained in:
parent
6e83154703
commit
4455615980
|
@ -0,0 +1,244 @@
|
||||||
|
/************************************************************************
|
||||||
|
* 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 <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
/* Headers from vtrutil library */
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "vtr_log.h"
|
||||||
|
|
||||||
|
#include "tileable_chan_details_builder.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* Adapt the number of channel width to a tileable routing architecture
|
||||||
|
***********************************************************************/
|
||||||
|
int adapt_to_tileable_route_chan_width(const int& chan_width,
|
||||||
|
const std::vector<t_segment_inf>& segment_infs) {
|
||||||
|
int tileable_chan_width = 0;
|
||||||
|
|
||||||
|
/* Estimate the number of segments per type by the given ChanW*/
|
||||||
|
std::vector<size_t> num_tracks_per_seg_type = get_num_tracks_per_seg_type(chan_width,
|
||||||
|
segment_infs,
|
||||||
|
true); /* Force to use the full segment group */
|
||||||
|
/* Sum-up the number of tracks */
|
||||||
|
for (size_t iseg = 0; iseg < num_tracks_per_seg_type.size(); ++iseg) {
|
||||||
|
tileable_chan_width += num_tracks_per_seg_type[iseg];
|
||||||
|
}
|
||||||
|
|
||||||
|
return tileable_chan_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* 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 */
|
||||||
|
}
|
||||||
|
VTR_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, false);
|
||||||
|
|
||||||
|
/* 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 or this is the last track in this group, we set an ending point */
|
||||||
|
if ( (seg_len - 1 == itrack % seg_len)
|
||||||
|
|| (itrack == num_tracks[iseg] - 1) ) {
|
||||||
|
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 */
|
||||||
|
VTR_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:
|
||||||
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||||
|
"Invalid device_side!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return chan_node_details;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef TILEABLE_CHAN_DETAILS_BUILDER_H
|
||||||
|
#define TILEABLE_CHAN_DETAILS_BUILDER_H
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Include header files that are required by function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
#include <vector>
|
||||||
|
#include "physical_types.h"
|
||||||
|
#include "chan_node_details.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
int adapt_to_tileable_route_chan_width(const int& chan_width, const std::vector<t_segment_inf>& segment_inf);
|
||||||
|
|
||||||
|
ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width, const size_t& max_seg_length,
|
||||||
|
const e_side& device_side,
|
||||||
|
const std::vector<t_segment_inf>& segment_inf);
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue