Merge branch 'tileable_routing' into multimode_clb
Conflicts: vpr7_x2p/vpr/regression_verilog.sh
This commit is contained in:
commit
d19b470b33
|
@ -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,19 +55,386 @@
|
||||||
#include "fpga_x2p_types.h"
|
#include "fpga_x2p_types.h"
|
||||||
#include "rr_graph_tileable_builder.h"
|
#include "rr_graph_tileable_builder.h"
|
||||||
|
|
||||||
|
#include "chan_node_details.h"
|
||||||
|
#include "device_coordinator.h"
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* Local function in the file
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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, enum e_pin_type pin_type, enum e_side pin_side, 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) {
|
||||||
|
if ( (1 == cur_grid.type->pinloc[pin_height][pin_side][ipin])
|
||||||
|
&& (pin_type == cur_grid.type->pin_class[ipin]) ) {
|
||||||
|
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, enum e_pin_type pin_type, 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;
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* Estimate the number of rr_nodes per category:
|
* Estimate the number of rr_nodes per category:
|
||||||
* CHANX, CHANY, IPIN, OPIN, SOURCE, SINK
|
* CHANX, CHANY, IPIN, OPIN, SOURCE, SINK
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
static
|
static
|
||||||
std::vector<size_t> estimate_num_rr_nodes_per_type() {
|
std::vector<size_t> estimate_num_rr_nodes_per_type(const DeviceCoordinator& device_size,
|
||||||
|
std::vector<std::vector<t_grid_tile>> grids,
|
||||||
|
std::vector<size_t> chan_width,
|
||||||
|
std::vector<t_segment_inf> segment_infs) {
|
||||||
std::vector<size_t> num_rr_nodes_per_type;
|
std::vector<size_t> num_rr_nodes_per_type;
|
||||||
|
/* reserve the vector:
|
||||||
|
* we have the follow type:
|
||||||
|
* SOURCE = 0, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES
|
||||||
|
* NUM_RR_TYPES and INTRA_CLUSTER_EDGE will be 0
|
||||||
|
*/
|
||||||
|
num_rr_nodes_per_type.resize(NUM_RR_TYPES);
|
||||||
|
/* Make sure a clean start */
|
||||||
|
for (size_t i = 0; i < NUM_RR_TYPES; ++i) {
|
||||||
|
num_rr_nodes_per_type[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* 1. Search the grid and find the number OPINs and IPINs per grid
|
||||||
|
* Note that the number of SOURCE nodes are the same as OPINs
|
||||||
|
* and the number of SINK nodes are the same as IPINs
|
||||||
|
***********************************************************************/
|
||||||
|
for (size_t ix = 0; ix < grids.size(); ++ix) {
|
||||||
|
for (size_t iy = 0; iy < grids[ix].size(); ++iy) {
|
||||||
|
/* Skip EMPTY tiles */
|
||||||
|
if (EMPTY_TYPE == grids[ix][iy].type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Skip height>1 tiles (mostly heterogeneous blocks) */
|
||||||
|
if (0 < grids[ix][iy].offset) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
enum e_side io_side = NUM_SIDES;
|
||||||
|
/* If this is the block on borders, we consider IO side */
|
||||||
|
if (IO_TYPE == grid[ix][iy].type) {
|
||||||
|
DeviceCoordinator io_device_size(device_size.get_x() - 1, device_size.get_y() - 1);
|
||||||
|
DeviceCoordinator grid_coordinator(ix, iy);
|
||||||
|
io_side = determine_io_grid_pin_side(device_size, grid_coordinator);
|
||||||
|
}
|
||||||
|
/* get the number of OPINs */
|
||||||
|
num_rr_nodes_per_type[OPIN] += get_grid_num_pins(grids[ix][iy], DRIVER, io_side);
|
||||||
|
/* get the number of IPINs */
|
||||||
|
num_rr_nodes_per_type[IPIN] += get_grid_num_pins(grids[ix][iy], RECEIVER, io_side);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* SOURCE and SINK */
|
||||||
|
num_rr_nodes_per_type[SOURCE] = num_rr_nodes_per_type[OPIN];
|
||||||
|
num_rr_nodes_per_type[SINK] = num_rr_nodes_per_type[IPIN];
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* 2. 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
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
***********************************************************************/
|
||||||
|
/* For X-direction Channel */
|
||||||
|
/* For LEFT side of FPGA */
|
||||||
|
ChanNodeDetails left_chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, LEFT, segment_infs);
|
||||||
|
for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) {
|
||||||
|
num_rr_nodes_per_type[CHANX] += left_chanx_details.get_num_starting_tracks();
|
||||||
|
}
|
||||||
|
/* For RIGHT side of FPGA */
|
||||||
|
ChanNodeDetails right_chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, RIGHT, segment_infs);
|
||||||
|
for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) {
|
||||||
|
num_rr_nodes_per_type[CHANX] += right_chanx_details.get_num_starting_tracks();
|
||||||
|
}
|
||||||
|
/* For core of FPGA */
|
||||||
|
ChanNodeDetails core_chanx_details = build_unidir_chan_node_details(chan_width[1], device_size.get_x() - 2, NUM_SIDES, segment_infs);
|
||||||
|
for (size_t ix = 1; ix < grids.size() - 2; ++ix) {
|
||||||
|
for (size_t iy = 1; iy < grids[ix].size() - 2; ++iy) {
|
||||||
|
num_rr_nodes_per_type[CHANX] += core_chanx_details.get_num_starting_tracks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For Y-direction Channel */
|
||||||
|
/* For TOP side of FPGA */
|
||||||
|
ChanNodeDetails top_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, TOP, segment_infs);
|
||||||
|
for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) {
|
||||||
|
num_rr_nodes_per_type[CHANY] += top_chany_details.get_num_starting_tracks();
|
||||||
|
}
|
||||||
|
/* For BOTTOM side of FPGA */
|
||||||
|
ChanNodeDetails bottom_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, BOTTOM, segment_infs);
|
||||||
|
for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) {
|
||||||
|
num_rr_nodes_per_type[CHANY] += bottom_chany_details.get_num_starting_tracks();
|
||||||
|
}
|
||||||
|
/* For core of FPGA */
|
||||||
|
ChanNodeDetails core_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, NUM_SIDES, segment_infs);
|
||||||
|
for (size_t ix = 1; ix < grids.size() - 2; ++ix) {
|
||||||
|
for (size_t iy = 1; iy < grids[ix].size() - 2; ++iy) {
|
||||||
|
num_rr_nodes_per_type[CHANY] += core_chany_details.get_num_starting_tracks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return num_rr_nodes_per_type;
|
return num_rr_nodes_per_type;
|
||||||
}
|
}
|
||||||
|
@ -122,9 +489,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 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 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,
|
INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings,
|
||||||
/*Xifan TANG: Switch Segment Pattern Support*/
|
/*Xifan TANG: Switch Segment Pattern Support*/
|
||||||
INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns,
|
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) {
|
INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) {
|
||||||
/* Create an empty graph */
|
/* Create an empty graph */
|
||||||
t_rr_graph rr_graph;
|
t_rr_graph rr_graph;
|
||||||
rr_graph.rr_node_indices = NULL;
|
rr_graph.rr_node_indices = NULL;
|
||||||
|
@ -134,31 +501,27 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
||||||
/* Reset warning flag */
|
/* Reset warning flag */
|
||||||
*Warnings = RR_GRAPH_NO_WARN;
|
*Warnings = RR_GRAPH_NO_WARN;
|
||||||
|
|
||||||
/************************************************************************
|
/* Create a matrix of grid */
|
||||||
* 1. Assign the segments for each routing channel,
|
DeviceCoordinator device_size(L_nx + 2, L_ny + 2);
|
||||||
* To be specific, for each routing track, we assign a routing segment.
|
std::vector< std::vector<t_grid_tile> > grids;
|
||||||
* The assignment is subject to users' specifications, such as
|
/* reserve vector capacity to be memory efficient */
|
||||||
* a. length of each type of segment
|
grids.resize(L_nx + 2);
|
||||||
* b. frequency of each type of segment.
|
for (int ix = 0; ix < (L_nx + 2); ++ix) {
|
||||||
* c. routing channel width
|
grids[ix].resize(L_ny + 2);
|
||||||
* IMPORTANT: we should be aware that channel width maybe different
|
for (int iy = 0; ix < (L_ny + 2); ++iy) {
|
||||||
* in X-direction and Y-direction channels!!!
|
grid[ix][iy] = L_grid[ix][iy];
|
||||||
* So we will load segment details for different channels
|
}
|
||||||
***********************************************************************/
|
}
|
||||||
/* Check the channel width */
|
/* Create a vector of channel width, we support X-direction and Y-direction has different W */
|
||||||
int nodes_per_chan = chan_width;
|
std::vector<size_t> device_chan_width;
|
||||||
assert(chan_width > 0);
|
device_chan_width.push_back(chan_width);
|
||||||
t_seg_details *seg_details = NULL;
|
device_chan_width.push_back(chan_width);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Predict the track index of each channel,
|
/* Create a vector of segment_inf */
|
||||||
* The track index, also called ptc_num of each CHANX and CHANY rr_node
|
std::vector<t_segment_inf> segment_infs;
|
||||||
* Will rotate by 2 in a uni-directional tileable routing architecture
|
for (int iseg = 0; iseg < num_seg_types; ++iseg) {
|
||||||
* Vectors are built here to record the ptc_num sequence in each channel
|
segment_infs.push_back(segment_inf[iseg]);
|
||||||
*/
|
}
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* 2. Estimate the number of nodes in the rr_graph
|
* 2. Estimate the number of nodes in the rr_graph
|
||||||
|
@ -169,8 +532,24 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
||||||
* d. SINK, virtual node which is connected to IPINs
|
* d. SINK, virtual node which is connected to IPINs
|
||||||
* e. CHANX and CHANY, routing segments of each channel
|
* e. CHANX and CHANY, routing segments of each channel
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
std::vector<size_t> num_rr_nodes_per_type = estimate_num_rr_nodes_per_type();
|
std::vector<size_t> num_rr_nodes_per_type = estimate_num_rr_nodes_per_type(device_size, grids, device_chan_width, segment_infs);
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* 3. Allocate the rr_nodes
|
||||||
|
***********************************************************************/
|
||||||
|
rr_graph.num_rr_nodes = 0;
|
||||||
|
for (size_t i = 0; i < num_rr_nodes_per_type.size(); ++i) {
|
||||||
|
rr_graph.num_rr_nodes += num_rr_nodes_per_type[i];
|
||||||
|
}
|
||||||
|
/* use calloc to initialize everything to be zero */
|
||||||
|
rr_graph.rr_node = (t_rr_node*)my_calloc(rr_graph.num_rr_nodes, sizeof(t_rr_node));
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* 4. Initialize the basic information of rr_nodes:
|
||||||
|
* coordinators: xlow, ylow, xhigh, yhigh,
|
||||||
|
* features: capacity, track_ids, ptc_num, direction
|
||||||
|
* grid_info : pb_graph_pin
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* 3. Create the connectivity of OPINs
|
* 3. Create the connectivity of OPINs
|
||||||
|
@ -180,7 +559,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
||||||
int **Fc_in = NULL; /* [0..num_types-1][0..num_pins-1] */
|
int **Fc_in = NULL; /* [0..num_types-1][0..num_pins-1] */
|
||||||
boolean Fc_clipped;
|
boolean Fc_clipped;
|
||||||
Fc_clipped = FALSE;
|
Fc_clipped = FALSE;
|
||||||
Fc_in = alloc_and_load_actual_fc(L_num_types, types, nodes_per_chan,
|
Fc_in = alloc_and_load_actual_fc(L_num_types, types, chan_width,
|
||||||
FALSE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0);
|
FALSE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0);
|
||||||
if (Fc_clipped) {
|
if (Fc_clipped) {
|
||||||
*Warnings |= RR_GRAPH_WARN_FC_CLIPPED;
|
*Warnings |= RR_GRAPH_WARN_FC_CLIPPED;
|
||||||
|
@ -193,7 +572,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
int **Fc_out = NULL; /* [0..num_types-1][0..num_pins-1] */
|
int **Fc_out = NULL; /* [0..num_types-1][0..num_pins-1] */
|
||||||
Fc_clipped = FALSE;
|
Fc_clipped = FALSE;
|
||||||
Fc_out = alloc_and_load_actual_fc(L_num_types, types, nodes_per_chan,
|
Fc_out = alloc_and_load_actual_fc(L_num_types, types, chan_width,
|
||||||
TRUE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0);
|
TRUE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0);
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
|
@ -204,6 +583,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
||||||
* c. handle direct-connections
|
* c. handle direct-connections
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
/* Alloc node lookups, count nodes, alloc rr nodes */
|
/* Alloc node lookups, count nodes, alloc rr nodes */
|
||||||
|
/*
|
||||||
rr_graph.num_rr_nodes = 0;
|
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.rr_node_indices = alloc_and_load_rr_node_indices(nodes_per_chan, L_nx, L_ny,
|
||||||
&(rr_graph.num_rr_nodes), seg_details);
|
&(rr_graph.num_rr_nodes), seg_details);
|
||||||
|
@ -211,6 +591,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);
|
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);
|
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);
|
memset(L_rr_edge_done, 0, sizeof(boolean) * rr_graph.num_rr_nodes);
|
||||||
|
*/
|
||||||
|
|
||||||
/* handle direct-connections */
|
/* handle direct-connections */
|
||||||
t_clb_to_clb_directs* clb_to_clb_directs = NULL;
|
t_clb_to_clb_directs* clb_to_clb_directs = NULL;
|
||||||
|
@ -223,7 +604,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
|
||||||
* a. cost_index
|
* a. cost_index
|
||||||
* b. RC tree
|
* b. RC tree
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
rr_graph_externals(timing_inf, segment_inf, num_seg_types, nodes_per_chan,
|
rr_graph_externals(timing_inf, segment_inf, num_seg_types, chan_width,
|
||||||
wire_to_ipin_switch, base_cost_type);
|
wire_to_ipin_switch, base_cost_type);
|
||||||
|
|
||||||
return rr_graph;
|
return rr_graph;
|
||||||
|
|
|
@ -403,7 +403,7 @@ void alloc_and_load_rr_graph_route_structs(t_rr_graph* local_rr_graph) {
|
||||||
|
|
||||||
int inode;
|
int inode;
|
||||||
|
|
||||||
local_rr_graph->rr_node_route_inf = (t_rr_node_route_inf *) my_malloc(local_rr_graph->num_rr_nodes * sizeof(t_rr_node_route_inf));
|
local_rr_graph->rr_node_route_inf = (t_rr_node_route_inf *) my_calloc(local_rr_graph->num_rr_nodes, sizeof(t_rr_node_route_inf));
|
||||||
|
|
||||||
for (inode = 0; inode < local_rr_graph->num_rr_nodes; inode++) {
|
for (inode = 0; inode < local_rr_graph->num_rr_nodes; inode++) {
|
||||||
local_rr_graph->rr_node_route_inf[inode].prev_node = NO_PREVIOUS;
|
local_rr_graph->rr_node_route_inf[inode].prev_node = NO_PREVIOUS;
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include "fpga_x2p_pbtypes_utils.h"
|
#include "fpga_x2p_pbtypes_utils.h"
|
||||||
#include "fpga_x2p_globals.h"
|
#include "fpga_x2p_globals.h"
|
||||||
|
|
||||||
|
#include "fpga_x2p_pb_rr_graph.h"
|
||||||
|
|
||||||
/* Count the number of rr_graph nodes that should be allocated
|
/* Count the number of rr_graph nodes that should be allocated
|
||||||
* (a) INPUT pins at the top-level pb_graph_node should be a local_rr_node and plus a SOURCE
|
* (a) INPUT pins at the top-level pb_graph_node should be a local_rr_node and plus a SOURCE
|
||||||
* (b) CLOCK pins at the top-level pb_graph_node should be a local_rr_node and plus a SOURCE
|
* (b) CLOCK pins at the top-level pb_graph_node should be a local_rr_node and plus a SOURCE
|
||||||
|
@ -104,6 +106,7 @@ void init_one_rr_node_pack_cost_for_phy_graph_node(INP t_pb_graph_pin* cur_pb_gr
|
||||||
|
|
||||||
|
|
||||||
/* Override the fan-in and fan-out for a top/primitive pb_graph_node */
|
/* Override the fan-in and fan-out for a top/primitive pb_graph_node */
|
||||||
|
static
|
||||||
void override_one_rr_node_for_top_primitive_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin,
|
void override_one_rr_node_for_top_primitive_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin,
|
||||||
INOUTP t_rr_graph* local_rr_graph,
|
INOUTP t_rr_graph* local_rr_graph,
|
||||||
int cur_rr_node_index,
|
int cur_rr_node_index,
|
||||||
|
@ -151,6 +154,7 @@ void override_one_rr_node_for_top_primitive_phy_pb_graph_node(INP t_pb_graph_pin
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize a rr_node in a rr_graph of phyical pb_graph_node */
|
/* initialize a rr_node in a rr_graph of phyical pb_graph_node */
|
||||||
|
static
|
||||||
void init_one_rr_node_for_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin,
|
void init_one_rr_node_for_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin,
|
||||||
INOUTP t_rr_graph* local_rr_graph,
|
INOUTP t_rr_graph* local_rr_graph,
|
||||||
int cur_rr_node_index,
|
int cur_rr_node_index,
|
||||||
|
@ -206,7 +210,9 @@ void init_one_rr_node_for_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin
|
||||||
local_rr_graph->rr_node[cur_rr_node_index].prev_edge = OPEN;
|
local_rr_graph->rr_node[cur_rr_node_index].prev_edge = OPEN;
|
||||||
|
|
||||||
local_rr_graph->rr_node[cur_rr_node_index].capacity = 1;
|
local_rr_graph->rr_node[cur_rr_node_index].capacity = 1;
|
||||||
|
local_rr_graph->rr_node[cur_rr_node_index].occ = 0;
|
||||||
local_rr_graph->rr_node[cur_rr_node_index].type = rr_node_type;
|
local_rr_graph->rr_node[cur_rr_node_index].type = rr_node_type;
|
||||||
|
local_rr_graph->rr_node[cur_rr_node_index].cost_index = 0;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -270,6 +276,7 @@ void connect_one_rr_node_for_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_
|
||||||
/* Recursively configure all the rr_nodes in the rr_graph
|
/* Recursively configure all the rr_nodes in the rr_graph
|
||||||
* Initialize the routing cost, fan-in rr_nodes and fan-out rr_nodes, and switches
|
* Initialize the routing cost, fan-in rr_nodes and fan-out rr_nodes, and switches
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
void rec_init_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_node,
|
void rec_init_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_node,
|
||||||
INOUTP t_rr_graph* local_rr_graph,
|
INOUTP t_rr_graph* local_rr_graph,
|
||||||
int* cur_rr_node_index) {
|
int* cur_rr_node_index) {
|
||||||
|
@ -418,6 +425,7 @@ void rec_init_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_n
|
||||||
/* Recursively connect all the rr_nodes in the rr_graph
|
/* Recursively connect all the rr_nodes in the rr_graph
|
||||||
* output_edges, output_switches
|
* output_edges, output_switches
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
void rec_connect_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_node,
|
void rec_connect_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_node,
|
||||||
INOUTP t_rr_graph* local_rr_graph,
|
INOUTP t_rr_graph* local_rr_graph,
|
||||||
int* cur_rr_node_index) {
|
int* cur_rr_node_index) {
|
||||||
|
@ -598,6 +606,7 @@ void alloc_and_load_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* top_pb_g
|
||||||
/* Check the vpack_net_num of a rr_node mapped to a pb_graph_pin and
|
/* Check the vpack_net_num of a rr_node mapped to a pb_graph_pin and
|
||||||
* mark the used vpack_net_num in the list
|
* mark the used vpack_net_num in the list
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
void mark_vpack_net_used_in_pb_pin(t_pb* cur_op_pb, t_pb_graph_pin* cur_pb_graph_pin,
|
void mark_vpack_net_used_in_pb_pin(t_pb* cur_op_pb, t_pb_graph_pin* cur_pb_graph_pin,
|
||||||
int L_num_vpack_nets, boolean* vpack_net_used_in_pb) {
|
int L_num_vpack_nets, boolean* vpack_net_used_in_pb) {
|
||||||
int inode;
|
int inode;
|
||||||
|
@ -621,6 +630,7 @@ void mark_vpack_net_used_in_pb_pin(t_pb* cur_op_pb, t_pb_graph_pin* cur_pb_graph
|
||||||
/* Recursively visit all the child pbs and
|
/* Recursively visit all the child pbs and
|
||||||
* mark the used vpack_net_num in the list
|
* mark the used vpack_net_num in the list
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
void mark_vpack_net_used_in_pb(t_pb* cur_op_pb,
|
void mark_vpack_net_used_in_pb(t_pb* cur_op_pb,
|
||||||
int L_num_vpack_nets, boolean* vpack_net_used_in_pb) {
|
int L_num_vpack_nets, boolean* vpack_net_used_in_pb) {
|
||||||
int mode_index, ipb, jpb;
|
int mode_index, ipb, jpb;
|
||||||
|
@ -718,6 +728,7 @@ void alloc_and_load_phy_pb_rr_graph_nets(INP t_pb* cur_op_pb,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the rr_node in the primitive node of a pb_rr_graph*/
|
/* Find the rr_node in the primitive node of a pb_rr_graph*/
|
||||||
|
static
|
||||||
void sync_pb_graph_pin_vpack_net_num_to_phy_pb(t_rr_node* cur_op_pb_rr_graph,
|
void sync_pb_graph_pin_vpack_net_num_to_phy_pb(t_rr_node* cur_op_pb_rr_graph,
|
||||||
t_pb_graph_pin* cur_pb_graph_pin,
|
t_pb_graph_pin* cur_pb_graph_pin,
|
||||||
t_rr_graph* local_rr_graph) {
|
t_rr_graph* local_rr_graph) {
|
||||||
|
@ -787,6 +798,7 @@ void sync_pb_graph_pin_vpack_net_num_to_phy_pb(t_rr_node* cur_op_pb_rr_graph,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
void rec_sync_wired_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb_graph_node* cur_pb_graph_node,
|
void rec_sync_wired_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb_graph_node* cur_pb_graph_node,
|
||||||
t_rr_node* op_pb_rr_graph,
|
t_rr_node* op_pb_rr_graph,
|
||||||
t_rr_graph* local_rr_graph) {
|
t_rr_graph* local_rr_graph) {
|
||||||
|
@ -851,6 +863,7 @@ void rec_sync_wired_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb_graph_node* cur_pb_
|
||||||
* synchronize the vpack_net_num of the top-level/primitive pb_graph_pin
|
* synchronize the vpack_net_num of the top-level/primitive pb_graph_pin
|
||||||
* to the physical pb rr_node nodes
|
* to the physical pb rr_node nodes
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
void rec_sync_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb* cur_op_pb,
|
void rec_sync_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb* cur_op_pb,
|
||||||
t_rr_graph* local_rr_graph) {
|
t_rr_graph* local_rr_graph) {
|
||||||
int mode_index, ipb, jpb;
|
int mode_index, ipb, jpb;
|
||||||
|
@ -921,6 +934,7 @@ void rec_sync_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb* cur_op_pb,
|
||||||
* 3. Find the SOURCE and SINK rr_nodes related to the pb_graph_pin
|
* 3. Find the SOURCE and SINK rr_nodes related to the pb_graph_pin
|
||||||
* 4. Configure the net_rr_terminals with the SINK/SOURCE rr_nodes
|
* 4. Configure the net_rr_terminals with the SINK/SOURCE rr_nodes
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
void alloc_and_load_phy_pb_rr_graph_net_rr_terminals(INP t_pb* cur_op_pb,
|
void alloc_and_load_phy_pb_rr_graph_net_rr_terminals(INP t_pb* cur_op_pb,
|
||||||
t_rr_graph* local_rr_graph) {
|
t_rr_graph* local_rr_graph) {
|
||||||
int inet, inode, rr_node_net_name;
|
int inet, inode, rr_node_net_name;
|
||||||
|
@ -1013,10 +1027,11 @@ void alloc_and_load_phy_pb_rr_graph_net_rr_terminals(INP t_pb* cur_op_pb,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
void alloc_pb_rr_graph_rr_indexed_data(t_rr_graph* local_rr_graph) {
|
void alloc_pb_rr_graph_rr_indexed_data(t_rr_graph* local_rr_graph) {
|
||||||
/* inside a cluster, I do not consider rr_indexed_data cost, set to 1 since other costs are multiplied by it */
|
/* inside a cluster, I do not consider rr_indexed_data cost, set to 1 since other costs are multiplied by it */
|
||||||
alloc_rr_graph_rr_indexed_data(local_rr_graph, 1);
|
alloc_rr_graph_rr_indexed_data(local_rr_graph, 1);
|
||||||
local_rr_graph->rr_indexed_data[0].base_cost = 1;
|
local_rr_graph->rr_indexed_data[0].base_cost = 1.;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1025,8 +1040,8 @@ void alloc_pb_rr_graph_rr_indexed_data(t_rr_graph* local_rr_graph) {
|
||||||
* Add an output edge to the rr_node of the used input
|
* Add an output edge to the rr_node of the used input
|
||||||
* connect it to the rr_node of the used LUT output
|
* connect it to the rr_node of the used LUT output
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
void add_rr_node_edge_to_one_wired_lut(t_pb_graph_node* cur_pb_graph_node,
|
void add_rr_node_edge_to_one_wired_lut(t_pb_graph_node* cur_pb_graph_node,
|
||||||
t_pb_type* cur_pb_type,
|
|
||||||
t_rr_node* op_pb_rr_graph,
|
t_rr_node* op_pb_rr_graph,
|
||||||
t_rr_graph* local_rr_graph) {
|
t_rr_graph* local_rr_graph) {
|
||||||
int iport, ipin;
|
int iport, ipin;
|
||||||
|
@ -1140,6 +1155,7 @@ void add_rr_node_edge_to_one_wired_lut(t_pb_graph_node* cur_pb_graph_node,
|
||||||
/* Add rr edges connecting from an input of a LUT to its output
|
/* Add rr edges connecting from an input of a LUT to its output
|
||||||
* IMPORTANT: this is only applied to LUT which operates in wire mode (a buffer)
|
* IMPORTANT: this is only applied to LUT which operates in wire mode (a buffer)
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
void rec_add_unused_rr_graph_wired_lut_rr_edges(INP t_pb_graph_node* cur_op_pb_graph_node,
|
void rec_add_unused_rr_graph_wired_lut_rr_edges(INP t_pb_graph_node* cur_op_pb_graph_node,
|
||||||
INP t_rr_node* cur_op_pb_rr_graph,
|
INP t_rr_node* cur_op_pb_rr_graph,
|
||||||
INOUTP t_rr_graph* local_rr_graph) {
|
INOUTP t_rr_graph* local_rr_graph) {
|
||||||
|
@ -1162,7 +1178,6 @@ void rec_add_unused_rr_graph_wired_lut_rr_edges(INP t_pb_graph_node* cur_op_pb_g
|
||||||
* connect it to the rr_node of the used LUT output
|
* connect it to the rr_node of the used LUT output
|
||||||
*/
|
*/
|
||||||
add_rr_node_edge_to_one_wired_lut(cur_op_pb_graph_node,
|
add_rr_node_edge_to_one_wired_lut(cur_op_pb_graph_node,
|
||||||
cur_pb_type,
|
|
||||||
cur_op_pb_rr_graph,
|
cur_op_pb_rr_graph,
|
||||||
local_rr_graph);
|
local_rr_graph);
|
||||||
}
|
}
|
||||||
|
@ -1194,6 +1209,7 @@ void rec_add_unused_rr_graph_wired_lut_rr_edges(INP t_pb_graph_node* cur_op_pb_g
|
||||||
/* Add rr edges connecting from an input of a LUT to its output
|
/* Add rr edges connecting from an input of a LUT to its output
|
||||||
* IMPORTANT: this is only applied to LUT which operates in wire mode (a buffer)
|
* IMPORTANT: this is only applied to LUT which operates in wire mode (a buffer)
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
void rec_add_rr_graph_wired_lut_rr_edges(INP t_pb* cur_op_pb,
|
void rec_add_rr_graph_wired_lut_rr_edges(INP t_pb* cur_op_pb,
|
||||||
INOUTP t_rr_graph* local_rr_graph) {
|
INOUTP t_rr_graph* local_rr_graph) {
|
||||||
int mode_index, ipb, jpb, imode;
|
int mode_index, ipb, jpb, imode;
|
||||||
|
@ -1214,7 +1230,6 @@ void rec_add_rr_graph_wired_lut_rr_edges(INP t_pb* cur_op_pb,
|
||||||
* connect it to the rr_node of the used LUT output
|
* connect it to the rr_node of the used LUT output
|
||||||
*/
|
*/
|
||||||
add_rr_node_edge_to_one_wired_lut(cur_op_pb->pb_graph_node,
|
add_rr_node_edge_to_one_wired_lut(cur_op_pb->pb_graph_node,
|
||||||
cur_pb_type,
|
|
||||||
cur_op_pb->rr_graph,
|
cur_op_pb->rr_graph,
|
||||||
local_rr_graph);
|
local_rr_graph);
|
||||||
}
|
}
|
||||||
|
@ -1253,6 +1268,7 @@ void rec_add_rr_graph_wired_lut_rr_edges(INP t_pb* cur_op_pb,
|
||||||
* For each multiple-source net, I add a new source as the unique source in routing purpose
|
* For each multiple-source net, I add a new source as the unique source in routing purpose
|
||||||
* As so, edges have to be added to the decendents of sources
|
* As so, edges have to be added to the decendents of sources
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
int add_virtual_sources_to_rr_graph_multi_sources(t_rr_graph* local_rr_graph) {
|
int add_virtual_sources_to_rr_graph_multi_sources(t_rr_graph* local_rr_graph) {
|
||||||
int inet, isrc;
|
int inet, isrc;
|
||||||
int unique_src_node;
|
int unique_src_node;
|
||||||
|
@ -1271,6 +1287,8 @@ int add_virtual_sources_to_rr_graph_multi_sources(t_rr_graph* local_rr_graph) {
|
||||||
unique_src_node = local_rr_graph->num_rr_nodes - 1;
|
unique_src_node = local_rr_graph->num_rr_nodes - 1;
|
||||||
local_rr_graph->rr_node[unique_src_node].type = SOURCE;
|
local_rr_graph->rr_node[unique_src_node].type = SOURCE;
|
||||||
local_rr_graph->rr_node[unique_src_node].capacity = 1;
|
local_rr_graph->rr_node[unique_src_node].capacity = 1;
|
||||||
|
local_rr_graph->rr_node[unique_src_node].occ = 0;
|
||||||
|
local_rr_graph->rr_node[unique_src_node].cost_index = 0;
|
||||||
local_rr_graph->rr_node[unique_src_node].fan_in = 0;
|
local_rr_graph->rr_node[unique_src_node].fan_in = 0;
|
||||||
local_rr_graph->rr_node[unique_src_node].num_drive_rr_nodes = 0;
|
local_rr_graph->rr_node[unique_src_node].num_drive_rr_nodes = 0;
|
||||||
local_rr_graph->rr_node[unique_src_node].drive_rr_nodes = NULL;
|
local_rr_graph->rr_node[unique_src_node].drive_rr_nodes = NULL;
|
||||||
|
@ -1314,6 +1332,9 @@ void alloc_and_load_rr_graph_for_phy_pb(INP t_pb* cur_op_pb,
|
||||||
/* Allocate rr_graph*/
|
/* Allocate rr_graph*/
|
||||||
cur_phy_pb->rr_graph = (t_rr_graph*) my_calloc(1, sizeof(t_rr_graph));
|
cur_phy_pb->rr_graph = (t_rr_graph*) my_calloc(1, sizeof(t_rr_graph));
|
||||||
|
|
||||||
|
/* Allocate and initialize cost index */
|
||||||
|
alloc_pb_rr_graph_rr_indexed_data(cur_phy_pb->rr_graph);
|
||||||
|
|
||||||
/* Create rr_graph */
|
/* Create rr_graph */
|
||||||
alloc_and_load_rr_graph_for_phy_pb_graph_node(cur_phy_pb->pb_graph_node, cur_phy_pb->rr_graph);
|
alloc_and_load_rr_graph_for_phy_pb_graph_node(cur_phy_pb->pb_graph_node, cur_phy_pb->rr_graph);
|
||||||
|
|
||||||
|
@ -1332,8 +1353,6 @@ void alloc_and_load_rr_graph_for_phy_pb(INP t_pb* cur_op_pb,
|
||||||
/* Allocate trace in rr_graph */
|
/* Allocate trace in rr_graph */
|
||||||
alloc_rr_graph_route_static_structs(cur_phy_pb->rr_graph, nx * ny); /* TODO: nx * ny should be reduced for pb-only routing */
|
alloc_rr_graph_route_static_structs(cur_phy_pb->rr_graph, nx * ny); /* TODO: nx * ny should be reduced for pb-only routing */
|
||||||
|
|
||||||
alloc_pb_rr_graph_rr_indexed_data(cur_phy_pb->rr_graph);
|
|
||||||
|
|
||||||
/* Fill the net_rr_terminals with
|
/* Fill the net_rr_terminals with
|
||||||
* 1. pin-to-pin mapping in pb_graph_node in cur_op_pb
|
* 1. pin-to-pin mapping in pb_graph_node in cur_op_pb
|
||||||
* 2. rr_graph in the cur_op_pb
|
* 2. rr_graph in the cur_op_pb
|
||||||
|
|
|
@ -201,6 +201,7 @@ static void power_usage_primitive(t_power_usage * power_usage, t_pb * pb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
void power_usage_local_pin_toggle(t_power_usage * power_usage, t_pb * pb,
|
void power_usage_local_pin_toggle(t_power_usage * power_usage, t_pb * pb,
|
||||||
t_pb_graph_pin * pin) {
|
t_pb_graph_pin * pin) {
|
||||||
float scale_factor;
|
float scale_factor;
|
||||||
|
@ -222,6 +223,7 @@ void power_usage_local_pin_toggle(t_power_usage * power_usage, t_pb * pb,
|
||||||
/ g_solution_inf.T_crit;
|
/ g_solution_inf.T_crit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
void power_usage_local_pin_buffer_and_wire(t_power_usage * power_usage,
|
void power_usage_local_pin_buffer_and_wire(t_power_usage * power_usage,
|
||||||
t_pb * pb, t_pb_graph_pin * pin) {
|
t_pb * pb, t_pb_graph_pin * pin) {
|
||||||
t_power_usage sub_power_usage;
|
t_power_usage sub_power_usage;
|
||||||
|
@ -1027,6 +1029,7 @@ static void power_usage_routing(t_power_usage * power_usage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
void power_alloc_and_init_pb_pin(t_pb_graph_pin * pin) {
|
void power_alloc_and_init_pb_pin(t_pb_graph_pin * pin) {
|
||||||
int port_idx;
|
int port_idx;
|
||||||
t_port * port_to_find;
|
t_port * port_to_find;
|
||||||
|
@ -1085,6 +1088,7 @@ void power_alloc_and_init_pb_pin(t_pb_graph_pin * pin) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
void power_init_pb_pins_rec(t_pb_graph_node * pb_node) {
|
void power_init_pb_pins_rec(t_pb_graph_node * pb_node) {
|
||||||
int mode;
|
int mode;
|
||||||
int type;
|
int type;
|
||||||
|
@ -1131,6 +1135,7 @@ void power_init_pb_pins_rec(t_pb_graph_node * pb_node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
void power_pb_pins_init() {
|
void power_pb_pins_init() {
|
||||||
int type_idx;
|
int type_idx;
|
||||||
|
|
||||||
|
@ -1141,6 +1146,7 @@ void power_pb_pins_init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
void power_routing_init(t_det_routing_arch * routing_arch) {
|
void power_routing_init(t_det_routing_arch * routing_arch) {
|
||||||
int net_idx;
|
int net_idx;
|
||||||
int rr_node_idx;
|
int rr_node_idx;
|
||||||
|
@ -1367,7 +1373,7 @@ boolean power_uninit(void) {
|
||||||
}
|
}
|
||||||
delete mux_info;
|
delete mux_info;
|
||||||
}
|
}
|
||||||
free(g_power_commonly_used);
|
delete g_power_commonly_used;
|
||||||
|
|
||||||
if (g_power_output->out) {
|
if (g_power_output->out) {
|
||||||
fclose(g_power_output->out);
|
fclose(g_power_output->out);
|
||||||
|
|
Loading…
Reference in New Issue