2020-02-18 19:35:00 -06:00
/******************************************************************************
* Memember functions for data structure LbRouter
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-02-18 22:51:03 -06:00
# include <queue>
2020-02-18 19:35:00 -06:00
# include "vtr_assert.h"
2020-02-18 20:22:36 -06:00
# include "vtr_log.h"
2020-02-18 19:35:00 -06:00
2020-02-19 01:07:36 -06:00
# include "physical_types.h"
# include "pb_type_graph.h"
# include "vpr_error.h"
# include "lb_rr_graph_utils.h"
2020-02-18 19:35:00 -06:00
# include "lb_router.h"
/* begin namespace openfpga */
namespace openfpga {
2020-02-18 20:22:36 -06:00
/**************************************************
* Public Constructors
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-02-19 12:09:24 -06:00
LbRouter : : LbRouter ( const LbRRGraph & lb_rr_graph , t_logical_block_type_ptr lb_type ) {
2020-02-18 20:22:36 -06:00
routing_status_ . resize ( lb_rr_graph . nodes ( ) . size ( ) ) ;
explored_node_tb_ . resize ( lb_rr_graph . nodes ( ) . size ( ) ) ;
explore_id_index_ = 1 ;
2020-02-19 12:09:24 -06:00
lb_type_ = lb_type ;
2020-02-18 20:22:36 -06:00
/* Default routing parameters */
params_ . max_iterations = 50 ;
params_ . pres_fac = 1 ;
params_ . pres_fac_mult = 2 ;
params_ . hist_fac = 0.3 ;
2020-02-19 15:53:35 -06:00
is_routed_ = false ;
2020-02-18 20:22:36 -06:00
pres_con_fac_ = 1 ;
}
2020-02-18 19:35:00 -06:00
/**************************************************
* Public Accessors
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
std : : vector < LbRRNodeId > LbRouter : : find_congested_rr_nodes ( const LbRRGraph & lb_rr_graph ) const {
2020-02-18 20:22:36 -06:00
/* Validate if the rr_graph is the one we used to initialize the router */
VTR_ASSERT ( true = = matched_lb_rr_graph ( lb_rr_graph ) ) ;
2020-02-18 19:35:00 -06:00
std : : vector < LbRRNodeId > congested_rr_nodes ;
for ( const LbRRNodeId & inode : lb_rr_graph . nodes ( ) ) {
if ( routing_status_ [ inode ] . occ > lb_rr_graph . node_capacity ( inode ) ) {
congested_rr_nodes . push_back ( inode ) ;
}
}
return congested_rr_nodes ;
}
2020-02-19 15:53:35 -06:00
bool LbRouter : : is_routed ( ) const {
return is_routed_ ;
}
/**************************************************
* Private accessors
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-02-18 20:22:36 -06:00
bool LbRouter : : is_route_success ( const LbRRGraph & lb_rr_graph ) const {
/* Validate if the rr_graph is the one we used to initialize the router */
VTR_ASSERT ( true = = matched_lb_rr_graph ( lb_rr_graph ) ) ;
for ( const LbRRNodeId & inode : lb_rr_graph . nodes ( ) ) {
if ( routing_status_ [ inode ] . occ > lb_rr_graph . node_capacity ( inode ) ) {
return false ;
}
}
return true ;
}
LbRouter : : t_trace * LbRouter : : find_node_in_rt ( t_trace * rt , const LbRRNodeId & rt_index ) {
t_trace * cur ;
if ( rt - > current_node = = rt_index ) {
return rt ;
} else {
for ( unsigned int i = 0 ; i < rt - > next_nodes . size ( ) ; i + + ) {
cur = find_node_in_rt ( & rt - > next_nodes [ i ] , rt_index ) ;
if ( cur ! = nullptr ) {
return cur ;
}
}
}
return nullptr ;
}
2020-02-19 01:07:36 -06:00
bool LbRouter : : route_has_conflict ( const LbRRGraph & lb_rr_graph , t_trace * rt ) const {
t_mode * cur_mode = nullptr ;
for ( unsigned int i = 0 ; i < rt - > next_nodes . size ( ) ; i + + ) {
std : : vector < LbRREdgeId > edges = lb_rr_graph . find_edge ( rt - > current_node , rt - > next_nodes [ i ] . current_node ) ;
VTR_ASSERT ( 0 = = edges . size ( ) ) ;
t_mode * new_mode = lb_rr_graph . edge_mode ( edges [ 0 ] ) ;
if ( cur_mode ! = nullptr & & cur_mode ! = new_mode ) {
return true ;
}
if ( route_has_conflict ( lb_rr_graph , & rt - > next_nodes [ i ] ) = = true ) {
return true ;
}
cur_mode = new_mode ;
}
return false ;
}
2020-02-19 12:09:24 -06:00
/**************************************************
* Public mutators
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool LbRouter : : try_route ( const LbRRGraph & lb_rr_graph ,
const AtomNetlist & atom_nlist ,
const int & verbosity ) {
/* Validate if the rr_graph is the one we used to initialize the router */
VTR_ASSERT ( true = = matched_lb_rr_graph ( lb_rr_graph ) ) ;
2020-02-19 15:53:35 -06:00
is_routed_ = false ;
2020-02-19 12:09:24 -06:00
bool is_impossible = false ;
mode_status_ . is_mode_conflict = false ;
mode_status_ . try_expand_all_modes = false ;
t_expansion_node exp_node ;
reset_explored_node_tb ( ) ;
/* Reset current routing */
reset_net_rt ( ) ;
reset_routing_status ( ) ;
std : : unordered_map < const t_pb_graph_node * , const t_mode * > mode_map ;
/* Iteratively remove congestion until a successful route is found.
* Cap the total number of iterations tried so that if a solution does not exist , then the router won ' t run indefinitely */
pres_con_fac_ = params_ . pres_fac ;
2020-02-19 15:53:35 -06:00
for ( int iter = 0 ; iter < params_ . max_iterations & & ! is_routed_ & & ! is_impossible ; iter + + ) {
2020-02-19 12:09:24 -06:00
unsigned int inet ;
/* Iterate across all nets internal to logic block */
for ( inet = 0 ; inet < lb_nets_ . size ( ) & & ! is_impossible ; inet + + ) {
2020-02-19 16:09:25 -06:00
NetId idx = NetId ( inet ) ;
2020-02-19 12:09:24 -06:00
if ( is_skip_route_net ( lb_rr_graph , lb_nets_ [ idx ] . rt_tree ) ) {
continue ;
}
commit_remove_rt ( lb_rr_graph , lb_nets_ [ idx ] . rt_tree , RT_REMOVE , mode_map ) ;
free_net_rt ( lb_nets_ [ idx ] . rt_tree ) ;
lb_nets_ [ idx ] . rt_tree = nullptr ;
add_source_to_rt ( idx ) ;
/* Route each sink of net */
for ( unsigned int itarget = 1 ; itarget < lb_nets_ [ idx ] . terminals . size ( ) & & ! is_impossible ; itarget + + ) {
pq_ . clear ( ) ;
/* Get lowest cost next node, repeat until a path is found or if it is impossible to route */
expand_rt ( idx , idx ) ;
is_impossible = try_expand_nodes ( atom_nlist , lb_rr_graph , lb_nets_ [ idx ] , exp_node , itarget , mode_status_ . expand_all_modes , verbosity ) ;
if ( is_impossible & & ! mode_status_ . expand_all_modes ) {
mode_status_ . try_expand_all_modes = true ;
mode_status_ . expand_all_modes = true ;
break ;
}
if ( exp_node . node_index = = lb_nets_ [ idx ] . terminals [ itarget ] ) {
/* Net terminal is routed, add this to the route tree, clear data structures, and keep going */
is_impossible = add_to_rt ( lb_nets_ [ idx ] . rt_tree , exp_node . node_index , idx ) ;
}
if ( is_impossible ) {
VTR_LOG ( " Routing was impossible! \n " ) ;
} else if ( mode_status_ . expand_all_modes ) {
is_impossible = route_has_conflict ( lb_rr_graph , lb_nets_ [ idx ] . rt_tree ) ;
if ( is_impossible ) {
VTR_LOG ( " Routing was impossible due to modes! \n " ) ;
}
}
explore_id_index_ + + ;
if ( explore_id_index_ > 2000000000 ) {
/* overflow protection */
for ( const LbRRNodeId & id : lb_rr_graph . nodes ( ) ) {
explored_node_tb_ [ id ] . explored_id = OPEN ;
explored_node_tb_ [ id ] . enqueue_id = OPEN ;
explore_id_index_ = 1 ;
}
}
}
if ( ! is_impossible ) {
commit_remove_rt ( lb_rr_graph , lb_nets_ [ idx ] . rt_tree , RT_COMMIT , mode_map ) ;
if ( mode_status_ . is_mode_conflict ) {
is_impossible = true ;
}
}
}
if ( ! is_impossible ) {
is_routed_ = is_route_success ( lb_rr_graph ) ;
} else {
- - inet ;
VTR_LOGV ( verbosity < 3 , " Net '%s' is impossible to route within proposed %s cluster \n " ,
2020-02-19 16:09:25 -06:00
atom_nlist . net_name ( lb_nets_ [ NetId ( inet ) ] . atom_net_id ) . c_str ( ) , lb_type_ - > name ) ;
2020-02-19 12:09:24 -06:00
is_routed_ = false ;
}
pres_con_fac_ * = params_ . pres_fac_mult ;
}
/* TODO:
* Let user to decide to how proceed upon the routing results :
* - route success : save the results through public accessors to lb_nets_
* print the route results to files
* - route fail : report all the congestion nodes
*/
return is_routed_ ;
}
2020-02-18 20:22:36 -06:00
/**************************************************
* Private mutators
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-02-19 01:07:36 -06:00
void LbRouter : : fix_duplicate_equivalent_pins ( const AtomContext & atom_ctx ,
const LbRRGraph & lb_rr_graph ) {
for ( size_t ilb_net = 0 ; ilb_net < lb_nets_ . size ( ) ; + + ilb_net ) {
//Collect all the sink terminals indicies which target a particular node
std : : map < LbRRNodeId , std : : vector < int > > duplicate_terminals ;
2020-02-19 16:09:25 -06:00
for ( size_t iterm = 1 ; iterm < lb_nets_ [ NetId ( ilb_net ) ] . terminals . size ( ) ; + + iterm ) {
LbRRNodeId node = lb_nets_ [ NetId ( ilb_net ) ] . terminals [ iterm ] ;
2020-02-19 01:07:36 -06:00
duplicate_terminals [ node ] . push_back ( iterm ) ;
}
for ( auto kv : duplicate_terminals ) {
if ( kv . second . size ( ) < 2 ) continue ; //Only process duplicates
//Remap all the duplicate terminals so they target the pin instead of the sink
for ( size_t idup_term = 0 ; idup_term < kv . second . size ( ) ; + + idup_term ) {
int iterm = kv . second [ idup_term ] ; //The index in terminals which is duplicated
2020-02-19 16:09:25 -06:00
VTR_ASSERT ( lb_nets_ [ NetId ( ilb_net ) ] . atom_pins . size ( ) = = lb_nets_ [ NetId ( ilb_net ) ] . terminals . size ( ) ) ;
AtomPinId atom_pin = lb_nets_ [ NetId ( ilb_net ) ] . atom_pins [ iterm ] ;
2020-02-19 01:07:36 -06:00
VTR_ASSERT ( atom_pin ) ;
const t_pb_graph_pin * pb_graph_pin = find_pb_graph_pin ( atom_ctx . nlist , atom_ctx . lookup , atom_pin ) ;
VTR_ASSERT ( pb_graph_pin ) ;
if ( pb_graph_pin - > port - > equivalent = = PortEquivalence : : NONE ) continue ; //Only need to remap equivalent ports
//Remap this terminal to an explicit pin instead of the common sink
LbRRNodeId pin_index = lb_rr_graph . find_node ( LB_INTERMEDIATE , pb_graph_pin ) ;
VTR_ASSERT ( true = = lb_rr_graph . valid_node_id ( pin_index ) ) ;
VTR_LOG_WARN (
" Found duplicate nets connected to logically equivalent pins. "
" Remapping intra lb net %d (atom net %zu '%s') from common sink "
" pb_route %d to fixed pin pb_route %d \n " ,
2020-02-19 16:09:25 -06:00
ilb_net , size_t ( lb_nets_ [ NetId ( ilb_net ) ] . atom_net_id ) , atom_ctx . nlist . net_name ( lb_nets_ [ NetId ( ilb_net ) ] . atom_net_id ) . c_str ( ) ,
2020-02-19 01:07:36 -06:00
kv . first , size_t ( pin_index ) ) ;
VTR_ASSERT ( 1 = = lb_rr_graph . node_out_edges ( pin_index , & ( pb_graph_pin - > parent_node - > pb_type - > modes [ 0 ] ) ) . size ( ) ) ;
LbRRNodeId sink_index = lb_rr_graph . edge_sink_node ( lb_rr_graph . node_out_edges ( pin_index , & ( pb_graph_pin - > parent_node - > pb_type - > modes [ 0 ] ) ) [ 0 ] ) ;
VTR_ASSERT ( LB_SINK = = lb_rr_graph . node_type ( sink_index ) ) ;
2020-02-19 16:09:25 -06:00
VTR_ASSERT_MSG ( sink_index = = lb_nets_ [ NetId ( ilb_net ) ] . terminals [ iterm ] , " Remapped pin must be connected to original sink " ) ;
2020-02-19 01:07:36 -06:00
//Change the target
2020-02-19 16:09:25 -06:00
lb_nets_ [ NetId ( ilb_net ) ] . terminals [ iterm ] = pin_index ;
2020-02-19 01:07:36 -06:00
}
}
}
}
// Check one edge for mode conflict.
bool LbRouter : : check_edge_for_route_conflicts ( std : : unordered_map < const t_pb_graph_node * , const t_mode * > & mode_map ,
const t_pb_graph_pin * driver_pin ,
const t_pb_graph_pin * pin ) {
if ( driver_pin = = nullptr ) {
return false ;
}
// Only check pins that are OUT_PORTs.
if ( pin = = nullptr | | pin - > port = = nullptr | | pin - > port - > type ! = OUT_PORT ) {
return false ;
}
VTR_ASSERT ( ! pin - > port - > is_clock ) ;
auto * pb_graph_node = pin - > parent_node ;
VTR_ASSERT ( pb_graph_node - > pb_type = = pin - > port - > parent_pb_type ) ;
const t_pb_graph_edge * edge = get_edge_between_pins ( driver_pin , pin ) ;
VTR_ASSERT ( edge ! = nullptr ) ;
auto mode_of_edge = edge - > interconnect - > parent_mode_index ;
auto * mode = & pb_graph_node - > pb_type - > modes [ mode_of_edge ] ;
auto result = mode_map . insert ( std : : make_pair ( pb_graph_node , mode ) ) ;
if ( ! result . second ) {
if ( result . first - > second ! = mode ) {
VTR_LOG ( " Differing modes for block. Got %s mode, while previously was %s for interconnect %s. \n " ,
mode - > name , result . first - > second - > name ,
edge - > interconnect - > name ) ;
// The illegal mode is added to the pb_graph_node as it resulted in a conflict during atom-to-atom routing. This mode cannot be used in the consequent cluster
// generation try.
2020-02-19 15:53:35 -06:00
auto it = illegal_modes_ . find ( pb_graph_node ) ;
if ( it = = illegal_modes_ . end ( ) ) {
illegal_modes_ [ pb_graph_node ] . push_back ( result . first - > second ) ;
} else {
if ( std : : find ( illegal_modes_ . at ( pb_graph_node ) . begin ( ) , illegal_modes_ . at ( pb_graph_node ) . end ( ) , result . first - > second ) = = illegal_modes_ . at ( pb_graph_node ) . end ( ) ) {
it - > second . push_back ( result . first - > second ) ;
}
2020-02-19 01:07:36 -06:00
}
// If the number of illegal modes equals the number of available mode for a specific pb_graph_node it means that no cluster can be generated. This resuts
// in a fatal error.
2020-02-19 15:53:35 -06:00
if ( ( int ) illegal_modes_ . at ( pb_graph_node ) . size ( ) > = pb_graph_node - > pb_type - > num_modes ) {
2020-02-19 01:07:36 -06:00
VPR_FATAL_ERROR ( VPR_ERROR_PACK , " There are no more available modes to be used. Routing Failed! " ) ;
}
return true ;
}
}
return false ;
}
void LbRouter : : commit_remove_rt ( const LbRRGraph & lb_rr_graph ,
t_trace * rt ,
const e_commit_remove & op ,
2020-02-19 12:09:24 -06:00
std : : unordered_map < const t_pb_graph_node * , const t_mode * > & mode_map ) {
2020-02-19 01:07:36 -06:00
int incr ;
if ( nullptr = = rt ) {
return ;
}
LbRRNodeId inode = rt - > current_node ;
/* Determine if node is being used or removed */
if ( op = = RT_COMMIT ) {
incr = 1 ;
if ( routing_status_ [ inode ] . occ > = lb_rr_graph . node_capacity ( inode ) ) {
routing_status_ [ inode ] . historical_usage + = ( routing_status_ [ inode ] . occ - lb_rr_graph . node_capacity ( inode ) + 1 ) ; /* store historical overuse */
}
} else {
incr = - 1 ;
2020-02-19 16:09:25 -06:00
explored_node_tb_ [ inode ] . inet = NetId : : INVALID ( ) ;
2020-02-19 01:07:36 -06:00
}
routing_status_ [ inode ] . occ + = incr ;
VTR_ASSERT ( routing_status_ [ inode ] . occ > = 0 ) ;
t_pb_graph_pin * driver_pin = lb_rr_graph . node_pb_graph_pin ( inode ) ;
/* Recursively update route tree */
for ( unsigned int i = 0 ; i < rt - > next_nodes . size ( ) ; i + + ) {
// Check to see if there is no mode conflict between previous nets.
// A conflict is present if there are differing modes between a pb_graph_node
// and its children.
2020-02-19 12:09:24 -06:00
if ( op = = RT_COMMIT & & mode_status_ . try_expand_all_modes ) {
2020-02-19 01:07:36 -06:00
const LbRRNodeId & node = rt - > next_nodes [ i ] . current_node ;
t_pb_graph_pin * pin = lb_rr_graph . node_pb_graph_pin ( node ) ;
if ( check_edge_for_route_conflicts ( mode_map , driver_pin , pin ) ) {
2020-02-19 12:09:24 -06:00
mode_status_ . is_mode_conflict = true ;
2020-02-19 01:07:36 -06:00
}
}
2020-02-19 12:09:24 -06:00
commit_remove_rt ( lb_rr_graph , & rt - > next_nodes [ i ] , op , mode_map ) ;
2020-02-19 01:07:36 -06:00
}
}
2020-02-18 23:08:51 -06:00
bool LbRouter : : is_skip_route_net ( const LbRRGraph & lb_rr_graph ,
t_trace * rt ) {
/* Validate if the rr_graph is the one we used to initialize the router */
VTR_ASSERT ( true = = matched_lb_rr_graph ( lb_rr_graph ) ) ;
if ( rt = = nullptr ) {
return false ; /* Net is not routed, therefore must route net */
}
LbRRNodeId inode = rt - > current_node ;
/* Determine if node is overused */
if ( routing_status_ [ inode ] . occ > lb_rr_graph . node_capacity ( inode ) ) {
/* Conflict between this net and another net at this node, reroute net */
return false ;
}
/* Recursively check that rest of route tree does not have a conflict */
for ( unsigned int i = 0 ; i < rt - > next_nodes . size ( ) ; i + + ) {
if ( ! is_skip_route_net ( lb_rr_graph , & rt - > next_nodes [ i ] ) ) {
return false ;
}
2020-02-18 20:22:36 -06:00
}
2020-02-18 23:08:51 -06:00
/* No conflict, this net's current route is legal, skip routing this net */
return true ;
2020-02-18 20:22:36 -06:00
}
2020-02-19 16:09:25 -06:00
bool LbRouter : : add_to_rt ( t_trace * rt , const LbRRNodeId & node_index , const NetId & irt_net ) {
2020-02-18 20:22:36 -06:00
std : : vector < LbRRNodeId > trace_forward ;
t_trace * link_node ;
t_trace curr_node ;
/* Store path all the way back to route tree */
LbRRNodeId rt_index = node_index ;
while ( explored_node_tb_ [ rt_index ] . inet ! = irt_net ) {
trace_forward . push_back ( rt_index ) ;
rt_index = explored_node_tb_ [ rt_index ] . prev_index ;
VTR_ASSERT ( rt_index ! = LbRRNodeId : : INVALID ( ) ) ;
}
/* Find rt_index on the route tree */
link_node = find_node_in_rt ( rt , rt_index ) ;
if ( link_node = = nullptr ) {
VTR_LOG ( " Link node is nullptr. Routing impossible " ) ;
return true ;
}
/* Add path to root tree */
LbRRNodeId trace_index ;
while ( ! trace_forward . empty ( ) ) {
trace_index = trace_forward . back ( ) ;
curr_node . current_node = trace_index ;
link_node - > next_nodes . push_back ( curr_node ) ;
link_node = & link_node - > next_nodes . back ( ) ;
trace_forward . pop_back ( ) ;
}
return false ;
}
2020-02-19 16:09:25 -06:00
void LbRouter : : add_source_to_rt ( const NetId & inet ) {
2020-02-18 23:08:51 -06:00
/* TODO: Validate net id */
VTR_ASSERT ( nullptr = = lb_nets_ [ inet ] . rt_tree ) ;
lb_nets_ [ inet ] . rt_tree = new t_trace ;
lb_nets_ [ inet ] . rt_tree - > current_node = lb_nets_ [ inet ] . terminals [ 0 ] ;
}
2020-02-18 23:01:22 -06:00
void LbRouter : : expand_rt_rec ( t_trace * rt ,
const LbRRNodeId & prev_index ,
2020-02-19 16:09:25 -06:00
const NetId & irt_net ,
2020-02-18 23:01:22 -06:00
const int & explore_id_index ) {
t_expansion_node enode ;
/* Perhaps should use a cost other than zero */
enode . cost = 0 ;
enode . node_index = rt - > current_node ;
enode . prev_index = prev_index ;
2020-02-19 12:09:24 -06:00
pq_ . push ( enode ) ;
2020-02-18 23:01:22 -06:00
explored_node_tb_ [ enode . node_index ] . inet = irt_net ;
explored_node_tb_ [ enode . node_index ] . explored_id = OPEN ;
explored_node_tb_ [ enode . node_index ] . enqueue_id = explore_id_index ;
explored_node_tb_ [ enode . node_index ] . enqueue_cost = 0 ;
explored_node_tb_ [ enode . node_index ] . prev_index = prev_index ;
for ( unsigned int i = 0 ; i < rt - > next_nodes . size ( ) ; i + + ) {
2020-02-19 12:09:24 -06:00
expand_rt_rec ( & rt - > next_nodes [ i ] , rt - > current_node , irt_net , explore_id_index ) ;
2020-02-18 23:01:22 -06:00
}
}
2020-02-19 16:09:25 -06:00
void LbRouter : : expand_rt ( const NetId & inet ,
const NetId & irt_net ) {
2020-02-19 12:09:24 -06:00
VTR_ASSERT ( pq_ . empty ( ) ) ;
2020-02-18 23:01:22 -06:00
2020-02-19 12:09:24 -06:00
expand_rt_rec ( lb_nets_ [ inet ] . rt_tree , LbRRNodeId : : INVALID ( ) , irt_net , explore_id_index_ ) ;
2020-02-18 23:01:22 -06:00
}
2020-02-18 22:51:03 -06:00
void LbRouter : : expand_edges ( const LbRRGraph & lb_rr_graph ,
t_mode * mode ,
const LbRRNodeId & cur_inode ,
float cur_cost ,
2020-02-19 12:09:24 -06:00
int net_fanout ) {
2020-02-18 22:51:03 -06:00
/* Validate if the rr_graph is the one we used to initialize the router */
VTR_ASSERT ( true = = matched_lb_rr_graph ( lb_rr_graph ) ) ;
t_expansion_node enode ;
int usage ;
float incr_cost ;
for ( const LbRREdgeId & iedge : lb_rr_graph . node_out_edges ( cur_inode , mode ) ) {
/* Init new expansion node */
enode . prev_index = cur_inode ;
enode . node_index = lb_rr_graph . edge_sink_node ( iedge ) ;
enode . cost = cur_cost ;
/* Determine incremental cost of using expansion node */
usage = routing_status_ [ enode . node_index ] . occ + 1 - lb_rr_graph . node_capacity ( enode . node_index ) ;
incr_cost = lb_rr_graph . node_intrinsic_cost ( enode . node_index ) ;
incr_cost + = lb_rr_graph . edge_intrinsic_cost ( iedge ) ;
incr_cost + = params_ . hist_fac * routing_status_ [ enode . node_index ] . historical_usage ;
if ( usage > 0 ) {
incr_cost * = ( usage * pres_con_fac_ ) ;
}
/* Adjust cost so that higher fanout nets prefer higher fanout routing nodes while lower fanout nets prefer lower fanout routing nodes */
float fanout_factor = 1.0 ;
t_mode * next_mode = routing_status_ [ enode . node_index ] . mode ;
/* Assume first mode if a mode hasn't been forced. */
if ( nullptr = = next_mode ) {
next_mode = & ( lb_rr_graph . node_pb_graph_pin ( enode . node_index ) - > parent_node - > pb_type - > modes [ 0 ] ) ;
}
if ( lb_rr_graph . node_out_edges ( enode . node_index , next_mode ) . size ( ) > 1 ) {
fanout_factor = 0.85 + ( 0.25 / net_fanout ) ;
} else {
fanout_factor = 1.15 - ( 0.25 / net_fanout ) ;
}
incr_cost * = fanout_factor ;
enode . cost = cur_cost + incr_cost ;
/* Add to queue if cost is lower than lowest cost path to this enode */
if ( explored_node_tb_ [ enode . node_index ] . enqueue_id = = explore_id_index_ ) {
if ( enode . cost < explored_node_tb_ [ enode . node_index ] . enqueue_cost ) {
2020-02-19 12:09:24 -06:00
pq_ . push ( enode ) ;
2020-02-18 22:51:03 -06:00
}
} else {
explored_node_tb_ [ enode . node_index ] . enqueue_id = explore_id_index_ ;
explored_node_tb_ [ enode . node_index ] . enqueue_cost = enode . cost ;
2020-02-19 12:09:24 -06:00
pq_ . push ( enode ) ;
2020-02-18 22:51:03 -06:00
}
}
}
void LbRouter : : expand_node ( const LbRRGraph & lb_rr_graph ,
const t_expansion_node & exp_node ,
const int & net_fanout ) {
/* Validate if the rr_graph is the one we used to initialize the router */
VTR_ASSERT ( true = = matched_lb_rr_graph ( lb_rr_graph ) ) ;
t_expansion_node enode ;
LbRRNodeId cur_node = exp_node . node_index ;
float cur_cost = exp_node . cost ;
t_mode * mode = routing_status_ [ cur_node ] . mode ;
if ( nullptr = = mode ) {
mode = & ( lb_rr_graph . node_pb_graph_pin ( cur_node ) - > parent_node - > pb_type - > modes [ 0 ] ) ;
}
2020-02-19 12:09:24 -06:00
expand_edges ( lb_rr_graph , mode , cur_node , cur_cost , net_fanout ) ;
2020-02-18 22:51:03 -06:00
}
void LbRouter : : expand_node_all_modes ( const LbRRGraph & lb_rr_graph ,
const t_expansion_node & exp_node ,
const int & net_fanout ) {
/* Validate if the rr_graph is the one we used to initialize the router */
VTR_ASSERT ( true = = matched_lb_rr_graph ( lb_rr_graph ) ) ;
LbRRNodeId cur_inode = exp_node . node_index ;
float cur_cost = exp_node . cost ;
t_mode * cur_mode = routing_status_ [ cur_inode ] . mode ;
auto * pin = lb_rr_graph . node_pb_graph_pin ( cur_inode ) ;
for ( const LbRREdgeId & edge : lb_rr_graph . node_out_edges ( cur_inode ) ) {
t_mode * mode = lb_rr_graph . edge_mode ( edge ) ;
/* If a mode has been forced, only add edges from that mode, otherwise add edges from all modes. */
if ( cur_mode ! = nullptr & & mode ! = cur_mode ) {
continue ;
}
/* Check whether a mode is illegal. If it is then the node will not be expanded */
bool is_illegal = false ;
if ( pin ! = nullptr ) {
auto * pb_graph_node = pin - > parent_node ;
2020-02-19 15:53:35 -06:00
if ( 0 = = illegal_modes_ . count ( pb_graph_node ) ) {
continue ;
}
for ( auto illegal_mode : illegal_modes_ . at ( pb_graph_node ) ) {
if ( mode = = illegal_mode ) {
2020-02-18 22:51:03 -06:00
is_illegal = true ;
break ;
}
}
}
if ( is_illegal = = true ) {
continue ;
}
2020-02-19 12:09:24 -06:00
expand_edges ( lb_rr_graph , mode , cur_inode , cur_cost , net_fanout ) ;
2020-02-18 22:51:03 -06:00
}
}
2020-02-19 01:07:36 -06:00
bool LbRouter : : try_expand_nodes ( const AtomNetlist & atom_nlist ,
const LbRRGraph & lb_rr_graph ,
const t_net & lb_net ,
t_expansion_node & exp_node ,
const int & itarget ,
const bool & try_other_modes ,
const int & verbosity ) {
bool is_impossible = false ;
do {
2020-02-19 12:09:24 -06:00
if ( pq_ . empty ( ) ) {
2020-02-19 01:07:36 -06:00
/* No connection possible */
is_impossible = true ;
if ( verbosity > 3 ) {
//Print detailed debug info
AtomNetId net_id = lb_net . atom_net_id ;
AtomPinId driver_pin = lb_net . atom_pins [ 0 ] ;
AtomPinId sink_pin = lb_net . atom_pins [ itarget ] ;
LbRRNodeId driver_rr_node = lb_net . terminals [ 0 ] ;
LbRRNodeId sink_rr_node = lb_net . terminals [ itarget ] ;
VTR_LOG ( " \t \t \t No possible routing path from %s to %s: needed for net '%s' from net pin '%s' " ,
describe_lb_rr_node ( lb_rr_graph , driver_rr_node ) . c_str ( ) ,
describe_lb_rr_node ( lb_rr_graph , sink_rr_node ) . c_str ( ) ,
atom_nlist . net_name ( net_id ) . c_str ( ) ,
atom_nlist . pin_name ( driver_pin ) . c_str ( ) ) ;
VTR_LOGV ( sink_pin , " to net pin '%s' " , atom_nlist . pin_name ( sink_pin ) . c_str ( ) ) ;
VTR_LOG ( " \n " ) ;
}
} else {
2020-02-19 12:09:24 -06:00
exp_node = pq_ . top ( ) ;
pq_ . pop ( ) ;
2020-02-19 01:07:36 -06:00
LbRRNodeId exp_inode = exp_node . node_index ;
if ( explored_node_tb_ [ exp_inode ] . explored_id ! = explore_id_index_ ) {
/* First time node is popped implies path to this node is the lowest cost.
* If the node is popped a second time , then the path to that node is higher
* than this path so ignore .
*/
explored_node_tb_ [ exp_inode ] . explored_id = explore_id_index_ ;
explored_node_tb_ [ exp_inode ] . prev_index = exp_node . prev_index ;
if ( exp_inode ! = lb_net . terminals [ itarget ] ) {
if ( ! try_other_modes ) {
2020-02-19 12:09:24 -06:00
expand_node ( lb_rr_graph , exp_node , lb_net . terminals . size ( ) - 1 ) ;
2020-02-19 01:07:36 -06:00
} else {
2020-02-19 12:09:24 -06:00
expand_node_all_modes ( lb_rr_graph , exp_node , lb_net . terminals . size ( ) - 1 ) ;
2020-02-19 01:07:36 -06:00
}
}
}
}
} while ( exp_node . node_index ! = lb_net . terminals [ itarget ] & & ! is_impossible ) ;
return is_impossible ;
}
2020-02-18 20:22:36 -06:00
/**************************************************
* Private validators
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool LbRouter : : matched_lb_rr_graph ( const LbRRGraph & lb_rr_graph ) const {
return ( ( routing_status_ . size ( ) = = lb_rr_graph . nodes ( ) . size ( ) )
& & ( explored_node_tb_ . size ( ) = = lb_rr_graph . nodes ( ) . size ( ) ) ) ;
}
2020-02-18 23:08:51 -06:00
/**************************************************
* Private Initializer and cleaner
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void LbRouter : : reset_explored_node_tb ( ) {
for ( t_explored_node_stats & explored_node : explored_node_tb_ ) {
explored_node . prev_index = LbRRNodeId : : INVALID ( ) ;
explored_node . explored_id = OPEN ;
2020-02-19 16:09:25 -06:00
explored_node . inet = NetId : : INVALID ( ) ;
2020-02-18 23:08:51 -06:00
explored_node . enqueue_id = OPEN ;
explored_node . enqueue_cost = 0 ;
}
}
2020-02-19 12:09:24 -06:00
void LbRouter : : reset_net_rt ( ) {
for ( unsigned int inet = 0 ; inet < lb_nets_ . size ( ) ; inet + + ) {
2020-02-19 16:09:25 -06:00
free_net_rt ( lb_nets_ [ NetId ( inet ) ] . rt_tree ) ;
lb_nets_ [ NetId ( inet ) ] . rt_tree = nullptr ;
2020-02-19 12:09:24 -06:00
}
}
void LbRouter : : reset_routing_status ( ) {
for ( t_routing_status & status : routing_status_ ) {
status . historical_usage = 0 ;
status . occ = 0 ;
}
}
void LbRouter : : clear_nets ( ) {
reset_net_rt ( ) ;
for ( unsigned int i = 0 ; i < lb_nets_ . size ( ) ; i + + ) {
2020-02-19 16:09:25 -06:00
lb_nets_ [ NetId ( i ) ] . terminals . clear ( ) ;
2020-02-19 12:09:24 -06:00
}
lb_nets_ . clear ( ) ;
}
void LbRouter : : free_net_rt ( t_trace * lb_trace ) {
if ( lb_trace ! = nullptr ) {
for ( unsigned int i = 0 ; i < lb_trace - > next_nodes . size ( ) ; i + + ) {
free_lb_trace ( & lb_trace - > next_nodes [ i ] ) ;
}
lb_trace - > next_nodes . clear ( ) ;
delete lb_trace ;
}
}
void LbRouter : : free_lb_trace ( t_trace * lb_trace ) {
if ( lb_trace ! = nullptr ) {
for ( unsigned int i = 0 ; i < lb_trace - > next_nodes . size ( ) ; i + + ) {
free_lb_trace ( & lb_trace - > next_nodes [ i ] ) ;
}
lb_trace - > next_nodes . clear ( ) ;
}
}
2020-02-19 15:53:35 -06:00
void LbRouter : : reset_illegal_modes ( ) {
illegal_modes_ . clear ( ) ;
}
2020-02-18 19:35:00 -06:00
} /* end namespace openfpga */