2020-02-18 13:00:27 -06:00
# ifndef LB_ROUTER_H
# define LB_ROUTER_H
/********************************************************************
* Include header files that are required by function declaration
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-02-18 17:50:56 -06:00
# include <map>
# include <unordered_map>
2020-02-18 13:00:27 -06:00
# include <vector>
2020-02-20 21:26:20 -06:00
# include <queue>
2020-02-18 17:50:56 -06:00
# include "vtr_vector.h"
2020-02-19 16:09:25 -06:00
# include "vtr_strong_id.h"
2020-02-18 17:50:56 -06:00
2020-02-18 18:04:36 -06:00
# include "physical_types.h"
2020-02-19 01:07:36 -06:00
# include "vpr_context.h"
2020-02-18 17:50:56 -06:00
2020-02-21 12:29:00 -06:00
# include "vpr_device_annotation.h"
2020-02-18 17:50:56 -06:00
# include "lb_rr_graph.h"
2020-02-18 13:00:27 -06:00
/********************************************************************
* Function declaration
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* begin namespace openfpga */
namespace openfpga {
2020-03-11 22:05:06 -05:00
/********************************************************************
* A connection - driven router for programmable logic blocks
* The router supports routing multiple nets on a LbRRGraph object
* which models the routing resources in a programmable logic block
*
* Note :
* - This router will not build / allocate a LbRRGraph object
* Users must do it OUTSIDE this object ! ! !
* - This router supports multiple sources for single net
* which is more capable the original VPR lb_router
*
* How to use the router :
*
* // Create your own routing resource graph
* LbRRGraph lb_rr_graph = < your_lb_rr_graph_builder > ( ) ;
*
* // Create a router object
* LbRouter lb_router ( lb_rr_graph ) ;
*
* // Add nets to be routed
* std : : vector < LbRRNodeId > source_nodes = < find_your_source_node_in_your_lb_rr_graph > ( ) ;
* std : : vector < LbRRNodeId > sink_nodes = < find_your_sink_node_in_your_lb_rr_graph > ( ) ;
* LbNetId net = lb_router . create_net_to_route ( source_nodes , sink_nodes ) ;
* // Add more nets
*
* // Initialize the modes to expand routing
* // This is a must-do before running the router in the purpose of repacking!!!
* lb_router . set_physical_pb_modes ( lb_rr_graph , device_annotation ) ;
*
* // Run the router
* bool route_success = lb_router . try_route ( lb_rr_graph , atom_ctx . nlist , verbose ) ;
*
* // Check routing status
* if ( true = = route_success ) {
* // Succeed
* }
*
* // Read out routing results
* // Here is an example to check which nodes are mapped to the 'net' created before
* std : : vector < LbRRNodeId > routed_nodes = lb_router . net_routed_nodes ( net ) ;
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-02-18 17:50:56 -06:00
class LbRouter {
2020-02-19 16:09:25 -06:00
public : /* Strong ids */
struct net_id_tag ;
typedef vtr : : StrongId < net_id_tag > NetId ;
2020-02-22 23:10:32 -06:00
public : /* Types and ranges */
typedef vtr : : vector < NetId , NetId > : : const_iterator net_iterator ;
typedef vtr : : Range < net_iterator > net_range ;
2020-02-18 17:50:56 -06:00
public : /* Intra-Logic Block Routing Data Structures (by instance) */
/**************************************************************************
* Describes the status of a logic cluster_ctx . blocks routing resource node
* for a given logic cluster_ctx . blocks instance
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-02-18 18:04:36 -06:00
struct t_routing_status {
2020-02-18 17:50:56 -06:00
int occ ; /* Number of nets currently using this lb_rr_node */
t_mode * mode ; /* Mode that this rr_node is set to */
int historical_usage ; /* Historical usage of using this node */
2020-02-18 19:35:00 -06:00
t_routing_status ( ) {
2020-02-18 17:50:56 -06:00
occ = 0 ;
mode = nullptr ;
historical_usage = 0 ;
}
} ;
/**************************************************************************
* Data structure forming the route tree of a net within one logic cluster_ctx . blocks .
* A net is implemented using routing resource nodes .
* The t_lb_trace data structure records one of the nodes used by the net and the connections
* to other nodes
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct t_trace {
LbRRNodeId current_node ; /* current t_lb_type_rr_node used by net */
2020-02-18 19:35:00 -06:00
std : : vector < t_trace > next_nodes ; /* index of previous edge that drives current node */
2020-02-18 17:50:56 -06:00
} ;
/**************************************************************************
* Stores tuning parameters used by intra - logic cluster_ctx . blocks router
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct t_option {
int max_iterations ;
float pres_fac ;
float pres_fac_mult ;
float hist_fac ;
} ;
/**************************************************************************
* Node expanded by router
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct t_expansion_node {
LbRRNodeId node_index ; /* Index of logic cluster_ctx.blocks rr node this expansion node represents */
LbRRNodeId prev_index ; /* Index of logic cluster_ctx.blocks rr node that drives this expansion node */
float cost ;
t_expansion_node ( ) {
node_index = LbRRNodeId : : INVALID ( ) ;
prev_index = LbRRNodeId : : INVALID ( ) ;
cost = 0 ;
}
} ;
class compare_expansion_node {
public :
/* Returns true if t1 is earlier than t2 */
bool operator ( ) ( t_expansion_node & e1 , t_expansion_node & e2 ) {
if ( e1 . cost > e2 . cost ) {
return true ;
}
return false ;
}
} ;
/**************************************************************************
* Stores explored nodes by router
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct t_explored_node_stats {
LbRRNodeId prev_index ; /* Prevous node that drives this one */
int explored_id ; /* ID used to determine if this node has been explored */
2020-02-19 16:09:25 -06:00
NetId inet ; /* net index of route tree */
2020-02-18 17:50:56 -06:00
int enqueue_id ; /* ID used ot determine if this node has been pushed on exploration priority queue */
float enqueue_cost ; /* cost of node pused on exploration priority queue */
t_explored_node_stats ( ) {
prev_index = LbRRNodeId : : INVALID ( ) ;
explored_id = OPEN ;
enqueue_id = OPEN ;
2020-02-19 16:09:25 -06:00
inet = NetId : : INVALID ( ) ;
2020-02-18 17:50:56 -06:00
enqueue_cost = 0 ;
}
} ;
/**************************************************************************
* Stores status of mode selection during clustering
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct t_mode_selection_status {
bool is_mode_conflict = false ;
bool try_expand_all_modes = false ;
bool expand_all_modes = false ;
bool is_mode_issue ( ) {
return is_mode_conflict | | try_expand_all_modes ;
}
} ;
2020-02-18 20:22:36 -06:00
2020-02-18 22:51:03 -06:00
// TODO: check if this hacky class memory reserve thing is still necessary, if not, then delete
/* Packing uses a priority queue that requires a large number of elements.
* This backdoor
* allows me to use a priority queue where I can pre - allocate the # of elements
* in the underlying container
* for efficiency reasons . Note : Must use vector with this
*/
template < class T , class U , class V >
class reservable_pq : public std : : priority_queue < T , U , V > {
public :
typedef typename std : : priority_queue < T > : : size_type size_type ;
reservable_pq ( size_type capacity = 0 ) {
reserve ( capacity ) ;
cur_cap = capacity ;
}
void reserve ( size_type capacity ) {
this - > c . reserve ( capacity ) ;
cur_cap = capacity ;
}
void clear ( ) {
this - > c . clear ( ) ;
this - > c . reserve ( cur_cap ) ;
}
private :
size_type cur_cap ;
} ;
2020-02-19 01:07:36 -06:00
enum e_commit_remove {
RT_COMMIT ,
RT_REMOVE
} ;
2020-02-18 22:51:03 -06:00
2020-02-18 20:22:36 -06:00
public : /* Public constructors */
2020-02-19 12:09:24 -06:00
LbRouter ( const LbRRGraph & lb_rr_graph , t_logical_block_type_ptr lb_type ) ;
2020-02-18 19:35:00 -06:00
public : /* Public accessors */
2020-02-22 23:10:32 -06:00
/* Return the ids for all the nets to be routed */
net_range nets ( ) const ;
/* Return the atom net id for a net to be routed */
AtomNetId net_atom_net_id ( const NetId & net ) const ;
2020-02-18 19:35:00 -06:00
/**
2020-02-18 20:22:36 -06:00
* Find all the routing resource nodes that are over - used , which they are used more than their capacity
2020-02-18 19:35:00 -06:00
* This function is call to collect the nodes and router can reroute these net
*/
std : : vector < LbRRNodeId > find_congested_rr_nodes ( const LbRRGraph & lb_rr_graph ) const ;
2020-02-18 17:50:56 -06:00
2020-02-19 15:53:35 -06:00
/* Show if a valid routing solution has been founded or not */
bool is_routed ( ) const ;
2020-02-19 17:40:53 -06:00
/**
* Get the routing results for a Net
*/
std : : vector < LbRRNodeId > net_routed_nodes ( const NetId & net ) const ;
2020-02-19 16:37:22 -06:00
public : /* Public mutators */
/**
* Add net to be routed
*/
2020-03-12 20:21:13 -05:00
NetId create_net_to_route ( const std : : vector < LbRRNodeId > & sources ,
const std : : vector < LbRRNodeId > & terminals ) ;
2020-02-19 17:40:53 -06:00
void add_net_atom_net_id ( const NetId & net , const AtomNetId & atom_net ) ;
void add_net_atom_pins ( const NetId & net , const AtomPinId & src_pin , const std : : vector < AtomPinId > & terminal_pins ) ;
2020-02-19 16:37:22 -06:00
2020-02-21 12:29:00 -06:00
/* TODO: Initialize all the modes in routing status with the mode set in pb
* This is function used for general purpose packing
*/
/* Set all the modes in routing status with the physical mode defined in device annotation
* This method is used only in repacking for physical logical blocks
* Do NOT use it during the general purpose packing
*/
void set_physical_pb_modes ( const LbRRGraph & lb_rr_graph ,
const VprDeviceAnnotation & device_annotation ) ;
2020-02-19 16:37:22 -06:00
/**
* Perform routing algorithm on a given logical tile routing resource graph
* Note : the lb_rr_graph must be the same as you initilized the router ! ! !
*/
bool try_route ( const LbRRGraph & lb_rr_graph ,
const AtomNetlist & atom_nlist ,
2020-03-12 21:42:41 -05:00
const bool & verbosity ) ;
2020-02-19 16:37:22 -06:00
2020-02-19 15:53:35 -06:00
private : /* Private accessors */
2020-02-18 20:22:36 -06:00
/**
* Report if the routing is successfully done on a logical block routing resource graph
*/
bool is_route_success ( const LbRRGraph & lb_rr_graph ) const ;
/**
* Try to find a node in the routing traces recursively
* If not found , will return an empty pointer
*/
t_trace * find_node_in_rt ( t_trace * rt , const LbRRNodeId & rt_index ) ;
2020-02-19 01:07:36 -06:00
bool route_has_conflict ( const LbRRGraph & lb_rr_graph , t_trace * rt ) const ;
2020-02-19 17:40:53 -06:00
/* Recursively find all the nodes in the trace */
void rec_collect_trace_nodes ( const t_trace * trace , std : : vector < LbRRNodeId > & routed_nodes ) const ;
2020-02-18 20:22:36 -06:00
private : /* Private mutators */
2020-02-19 01:07:36 -06:00
/*It is possible that a net may connect multiple times to a logically equivalent set of primitive pins.
* The cluster router will only route one connection for a particular net to the common sink of the
* equivalent pins .
*
* To work around this , we fix all but one of these duplicate connections to route to specific pins ,
* ( instead of the common sink ) . This ensures a legal routing is produced and that the duplicate pins
* are not ' missing ' in the clustered netlist .
*/
void fix_duplicate_equivalent_pins ( const AtomContext & atom_ctx ,
const LbRRGraph & lb_rr_graph ) ;
bool 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 ) ;
void 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-18 23:08:51 -06:00
bool is_skip_route_net ( const LbRRGraph & lb_rr_graph , t_trace * rt ) ;
2020-02-19 16:09:25 -06:00
bool add_to_rt ( t_trace * rt , const LbRRNodeId & node_index , const NetId & irt_net ) ;
2020-03-12 14:44:14 -05:00
void add_source_to_rt ( const NetId & inet , const size_t & isrc ) ;
2020-02-18 23:01:22 -06:00
void 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 ) ;
2020-02-19 16:09:25 -06:00
void expand_rt ( const NetId & inet ,
2020-03-12 14:44:14 -05:00
const NetId & irt_net ,
const size_t & isrc ) ;
2020-02-18 22:51:03 -06:00
void 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
void expand_node ( const LbRRGraph & lb_rr_graph ,
const t_expansion_node & exp_node ,
const int & net_fanout ) ;
void expand_node_all_modes ( const LbRRGraph & lb_rr_graph ,
const t_expansion_node & exp_node ,
const int & net_fanout ) ;
2020-02-19 01:07:36 -06:00
bool try_expand_nodes ( const AtomNetlist & atom_nlist ,
const LbRRGraph & lb_rr_graph ,
2020-02-19 16:37:22 -06:00
const NetId & lb_net ,
2020-02-19 01:07:36 -06:00
t_expansion_node & exp_node ,
2020-03-12 14:44:14 -05:00
const int & isrc ,
2020-02-19 01:07:36 -06:00
const int & itarget ,
const bool & try_other_modes ,
2020-03-12 23:53:17 -05:00
const bool & verbosity ) ;
2020-03-12 12:05:38 -05:00
bool try_route_net ( const LbRRGraph & lb_rr_graph ,
const AtomNetlist & atom_nlist ,
const NetId & net_idx ,
t_expansion_node & exp_node ,
std : : unordered_map < const t_pb_graph_node * , const t_mode * > & mode_map ,
2020-03-12 21:42:41 -05:00
const bool & verbosity ) ;
2020-02-19 01:07:36 -06:00
2020-02-18 20:22:36 -06:00
private : /* Private validators */
/**
* Validate if the rr_graph is the one we used to initialize the router
*/
bool matched_lb_rr_graph ( const LbRRGraph & lb_rr_graph ) const ;
2020-02-19 17:40:53 -06:00
bool valid_net_id ( const NetId & net_id ) const ;
2020-02-19 21:34:30 -06:00
/* Validate that all the nets have
* - valid source , terminal nodes in lb routing resource graph
* - valid atom net and pin ids in atom netlist
*/
bool check_net ( const LbRRGraph & lb_rr_graph ,
const AtomNetlist & atom_nlist ,
const NetId & net ) const ;
2020-02-18 23:08:51 -06:00
private : /* Private initializer and cleaner */
void reset_explored_node_tb ( ) ;
2020-02-19 12:09:24 -06:00
void reset_net_rt ( ) ;
void reset_routing_status ( ) ;
2020-02-19 15:53:35 -06:00
void reset_illegal_modes ( ) ;
2020-02-19 12:09:24 -06:00
void clear_nets ( ) ;
void free_net_rt ( t_trace * lb_trace ) ;
void free_lb_trace ( t_trace * lb_trace ) ;
2020-02-18 23:08:51 -06:00
2020-02-18 17:50:56 -06:00
private : /* Stores all data needed by intra-logic cluster_ctx.blocks router */
/* Logical Netlist Info */
2020-03-12 14:44:14 -05:00
/* Pointer to vector of intra logic cluster_ctx.blocks nets and their connections */
vtr : : vector < NetId , NetId > lb_net_ids_ ;
/* index of atom net this intra_lb_net represents */
vtr : : vector < NetId , AtomNetId > lb_net_atom_net_ids_ ;
/* AtomPin's associated with each source nodes */
vtr : : vector < NetId , std : : vector < AtomPinId > > lb_net_atom_source_pins_ ;
/* AtomPin's associated with each sink nodes */
vtr : : vector < NetId , std : : vector < AtomPinId > > lb_net_atom_sink_pins_ ;
/* starting points of the intra_lb_net */
vtr : : vector < NetId , std : : vector < LbRRNodeId > > lb_net_sources_ ;
/* end points of the intra_lb_net */
vtr : : vector < NetId , std : : vector < LbRRNodeId > > lb_net_sinks_ ;
/* Route tree head for each source of each net */
vtr : : vector < NetId , std : : vector < t_trace * > > lb_net_rt_trees_ ;
2020-02-18 17:50:56 -06:00
/* Logical-to-physical mapping info */
2020-02-18 18:04:36 -06:00
vtr : : vector < LbRRNodeId , t_routing_status > routing_status_ ; /* [0..lb_type_graph->size()-1] Stats for each logic cluster_ctx.blocks rr node instance */
2020-02-18 17:50:56 -06:00
/* Stores state info during Pathfinder iterative routing */
vtr : : vector < LbRRNodeId , t_explored_node_stats > explored_node_tb_ ; /* [0..lb_type_graph->size()-1] Stores mode exploration and traceback info for nodes */
2020-02-18 18:04:36 -06:00
2020-02-18 17:50:56 -06:00
int explore_id_index_ ; /* used in conjunction with node_traceback to determine whether or not a location has been explored. By using a unique identifier every route, I don't have to clear the previous route exploration */
/* Current type */
t_logical_block_type_ptr lb_type_ ;
/* Parameters used by router */
2020-02-18 20:22:36 -06:00
t_option params_ ;
2020-02-18 17:50:56 -06:00
2020-02-19 12:09:24 -06:00
/* Stores whether or not the current logical-to-physical mapping has a routed solution */
2020-02-19 15:53:35 -06:00
bool is_routed_ ;
2020-02-19 12:09:24 -06:00
/* Stores the mode selection status when expanding the edges */
t_mode_selection_status mode_status_ ;
/* Stores state info of the priority queue in expanding edges during route */
reservable_pq < t_expansion_node , std : : vector < t_expansion_node > , compare_expansion_node > pq_ ;
2020-02-18 17:50:56 -06:00
2020-02-19 15:53:35 -06:00
/* Store the illegal modes for each pb_graph_node that is involved in the routing resource graph */
std : : map < const t_pb_graph_node * , std : : vector < const t_mode * > > illegal_modes_ ;
2020-02-18 17:50:56 -06:00
/* current congestion factor */
float pres_con_fac_ ;
} ;
2020-02-18 13:00:27 -06:00
} /* end namespace openfpga */
# endif