⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 route_common.c

📁 VPR布局布线源码
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <math.h>#include <stdio.h>#include <assert.h>#include "util.h"#include "vpr_types.h"#include "vpr_utils.h"#include "globals.h"#include "mst.h"#include "route_export.h"#include "route_common.h"#include "route_tree_timing.h"#include "route_timing.h"#include "route_breadth_first.h"#include "route_directed_search.h"#include "place_and_route.h"#include "rr_graph.h"/***************** Variables shared only by route modules *******************/t_rr_node_route_inf *rr_node_route_inf = NULL;	/* [0..num_rr_nodes-1] */struct s_bb *route_bb = NULL;	/* [0..num_nets-1]. Limits area in which each  */			      /* net must be routed.                         *//**************** Static variables local to route_common.c ******************/static struct s_heap **heap;	/* Indexed from [1..heap_size] */static int heap_size;		/* Number of slots in the heap array */static int heap_tail;		/* Index of first unused slot in the heap array *//* For managing my own list of currently free heap data structures.     */static struct s_heap *heap_free_head = NULL;/* For managing my own list of currently free trace data structures.    */static struct s_trace *trace_free_head = NULL;#ifdef DEBUGstatic int num_trace_allocated = 0;	/* To watch for memory leaks. */static int num_heap_allocated = 0;static int num_linked_f_pointer_allocated = 0;#endifstatic struct s_linked_f_pointer *rr_modified_head = NULL;static struct s_linked_f_pointer *linked_f_pointer_free_head = NULL;/*  The numbering relation between the channels and clbs is:               * *                                                                         * *  |   IO    | chan_   |   FB      | chan_   |   FB     |               * *  |grid[0][2]| y[0][2] | grid[1][2]  | y[1][2] |  grid[2][2]|               * *  +-------- +         +------------+         +-----------+               * *                                                           } capacity in * *   No channel          chan_x[1][1]          chan_x[2][1]  } chan_width  * *                                                           } _x[1]       * *  +---------+         +------------+         +-----------+               * *  |         | chan_   |            | chan_   |           |               * *  |  IO     | y[0][1] |    FB     | y[1][1] |   FB     |               * *  |grid[0][1]|         |  grid[1][1] |         | grid[2][1] |               * *  |         |         |            |         |           |               * *  +---------+         +------------+         +-----------+               * *                                                           } capacity in * *                      chan_x[1][0]           chan_x[2][0]  } chan_width  *  *                                                           } _x[0]       * *                      +------------+         +-----------+               * *              No      |            | No      |           |               * *            Channel   |    IO      | Channel |   IO      |               * *                      |  grid[1][0] |         | grid[2][0] |               * *                      |            |         |           |               * *                      +------------+         +-----------+               * *                                                                         * *             {=======}              {=======}                            * *            Capacity in            Capacity in                           * *          chan_width_y[0]        chan_width_y[1]                         * *                                                                         *//******************** Subroutines local to route_common.c *******************/static void free_trace_data(struct s_trace *tptr);static void load_route_bb(int bb_factor);static struct s_trace *alloc_trace_data(void);static void add_to_heap(struct s_heap *hptr);static struct s_heap *alloc_heap_data(void);static struct s_linked_f_pointer *alloc_linked_f_pointer(void);static t_ivec **alloc_and_load_clb_opins_used_locally(t_subblock_data						      subblock_data);static void adjust_one_rr_occ_and_pcost(int inode,					int add_or_sub,					float pres_fac);/************************** Subroutine definitions ***************************/voidsave_routing(struct s_trace **best_routing,	     t_ivec ** fb_opins_used_locally,	     t_ivec ** saved_clb_opins_used_locally){/* This routing frees any routing currently held in best routing,       * * then copies over the current routing (held in trace_head), and       * * finally sets trace_head and trace_tail to all NULLs so that the      * * connection to the saved routing is broken.  This is necessary so     * * that the next iteration of the router does not free the saved        * * routing elements.  Also saves any data about locally used clb_opins, * * since this is also part of the routing.                              */    int inet, iblk, iclass, ipin, num_local_opins;    struct s_trace *tptr, *tempptr;    t_type_ptr type;    for(inet = 0; inet < num_nets; inet++)	{/* Free any previously saved routing.  It is no longer best. */	    tptr = best_routing[inet];	    while(tptr != NULL)		{		    tempptr = tptr->next;		    free_trace_data(tptr);		    tptr = tempptr;		}/* Save a pointer to the current routing in best_routing. */	    best_routing[inet] = trace_head[inet];/* Set the current (working) routing to NULL so the current trace       * * elements won't be reused by the memory allocator.                    */	    trace_head[inet] = NULL;	    trace_tail[inet] = NULL;	}/* Save which OPINs are locally used.                           */    for(iblk = 0; iblk < num_blocks; iblk++)	{	    type = block[iblk].type;	    for(iclass = 0; iclass < type->num_class; iclass++)		{		    num_local_opins =			fb_opins_used_locally[iblk][iclass].nelem;		    for(ipin = 0; ipin < num_local_opins; ipin++)			{			    saved_clb_opins_used_locally[iblk][iclass].				list[ipin] =				fb_opins_used_locally[iblk][iclass].				list[ipin];			}		}	}}voidrestore_routing(struct s_trace **best_routing,		t_ivec ** fb_opins_used_locally,		t_ivec ** saved_clb_opins_used_locally){/* Deallocates any current routing in trace_head, and replaces it with    * * the routing in best_routing.  Best_routing is set to NULL to show that * * it no longer points to a valid routing.  NOTE:  trace_tail is not      * * restored -- it is set to all NULLs since it is only used in            * * update_traceback.  If you need trace_tail restored, modify this        * * routine.  Also restores the locally used opin data.                    */    int inet, iblk, ipin, iclass, num_local_opins;    t_type_ptr type;    for(inet = 0; inet < num_nets; inet++)	{	    /* Free any current routing. */	    free_traceback(inet);	    /* Set the current routing to the saved one. */	    trace_head[inet] = best_routing[inet];	    best_routing[inet] = NULL;	/* No stored routing. */	}/* Save which OPINs are locally used.                           */    for(iblk = 0; iblk < num_blocks; iblk++)	{	    type = block[iblk].type;	    for(iclass = 0; iclass < type->num_class; iclass++)		{		    num_local_opins =			fb_opins_used_locally[iblk][iclass].nelem;		    for(ipin = 0; ipin < num_local_opins; ipin++)			{			    fb_opins_used_locally[iblk][iclass].list[ipin] =				saved_clb_opins_used_locally[iblk][iclass].				list[ipin];			}		}	}}voidget_serial_num(void){/* This routine finds a "magic cookie" for the routing and prints it.    * * Use this number as a routing serial number to ensure that programming * * changes do not break the router.                                      */    int inet, serial_num, inode;    struct s_trace *tptr;    serial_num = 0;    for(inet = 0; inet < num_nets; inet++)	{/* Global nets will have null trace_heads (never routed) so they * * are not included in the serial number calculation.            */	    tptr = trace_head[inet];	    while(tptr != NULL)		{		    inode = tptr->index;		    serial_num +=			(inet + 1) * (rr_node[inode].xlow * (nx + 1) -				      rr_node[inode].yhigh);		    serial_num -= rr_node[inode].ptc_num * (inet + 1) * 10;		    serial_num -= rr_node[inode].type * (inet + 1) * 100;		    serial_num %= 2000000000;	/* Prevent overflow */		    tptr = tptr->next;		}	}    printf("Serial number (magic cookie) for the routing is: %d\n",	   serial_num);}booleantry_route(int width_fac,	  struct s_router_opts router_opts,	  struct s_det_routing_arch det_routing_arch,	  t_segment_inf * segment_inf,	  t_timing_inf timing_inf,	  float **net_slack,	  float **net_delay,	  t_chan_width_dist chan_width_dist,	  t_ivec ** fb_opins_used_locally,	  t_mst_edge ** mst,	  boolean * Fc_clipped){/* Attempts a routing via an iterated maze router algorithm.  Width_fac * * specifies the relative width of the channels, while the members of   * * router_opts determine the value of the costs assigned to routing     * * resource node, etc.  det_routing_arch describes the detailed routing * * architecture (connection and switch boxes) of the FPGA; it is used   * * only if a DETAILED routing has been selected.                        */    int tmp;    boolean success;	t_graph_type graph_type;	if(router_opts.route_type == GLOBAL) {		graph_type = GRAPH_GLOBAL;	} else {		graph_type = (det_routing_arch.directionality ==		    BI_DIRECTIONAL ? GRAPH_BIDIR : GRAPH_UNIDIR);	}/* Set the channel widths */    init_chan(width_fac, chan_width_dist);/* Free any old routing graph, if one exists. */    free_rr_graph();/* Set up the routing resource graph defined by this FPGA architecture. */    build_rr_graph(graph_type,		   num_types, type_descriptors, nx, ny, grid,		   chan_width_x[0], NULL,		   det_routing_arch.switch_block_type, det_routing_arch.Fs,		   det_routing_arch.num_segment, det_routing_arch.num_switch, segment_inf,		   det_routing_arch.global_route_switch,		   det_routing_arch.delayless_switch, timing_inf,		   det_routing_arch.wire_to_ipin_switch,		   router_opts.base_cost_type, &tmp);/* Allocate and load some additional rr_graph information needed only by * * the router.                                                           */    alloc_and_load_rr_node_route_structs();    init_route_structs(router_opts.bb_factor);    if(router_opts.router_algorithm == BREADTH_FIRST)	{	    printf("Confirming Router Algorithm: BREADTH_FIRST.\n");	    success =		try_breadth_first_route(router_opts, fb_opins_used_locally,					width_fac);	}    else if(router_opts.router_algorithm == TIMING_DRIVEN)	{			/* TIMING_DRIVEN route */	    printf("Confirming Router Algorithm: TIMING_DRIVEN.\n");	    assert(router_opts.route_type != GLOBAL);	    success =		try_timing_driven_route(router_opts, net_slack, net_delay,					fb_opins_used_locally);	}    else	{			/* Directed Search Routability Driven */	    printf("Confirming Router Algorithm: DIRECTED_SEARCH.\n");	    success =		try_directed_search_route(router_opts, fb_opins_used_locally,					  width_fac, mst);	}    free_rr_node_route_structs();    return (success);}booleanfeasible_routing(void){/* This routine checks to see if this is a resource-feasible routing.      * * That is, are all rr_node capacity limitations respected?  It assumes    * * that the occupancy arrays are up to date when it is called.             */    int inode;    for(inode = 0; inode < num_rr_nodes; inode++)	if(rr_node[inode].occ > rr_node[inode].capacity)	    return (FALSE);    return (TRUE);}voidpathfinder_update_one_cost(struct s_trace *route_segment_start,			   int add_or_sub,			   float pres_fac){/* This routine updates the occupancy and pres_cost of the rr_nodes that are * * affected by the portion of the routing of one net that starts at          * * route_segment_start.  If route_segment_start is trace_head[inet], the     * * cost of all the nodes in the routing of net inet are updated.  If         * * add_or_sub is -1 the net (or net portion) is ripped up, if it is 1 the    * * net is added to the routing.  The size of pres_fac determines how severly * * oversubscribed rr_nodes are penalized.                                    */    struct s_trace *tptr;    int inode, occ, capacity;    tptr = route_segment_start;    if(tptr == NULL)		/* No routing yet. */	return;    for(;;)	{	    inode = tptr->index;	    occ = rr_node[inode].occ + add_or_sub;	    capacity = rr_node[inode].capacity;	    rr_node[inode].occ = occ;/* pres_cost is Pn in the Pathfinder paper. I set my pres_cost according to * * the overuse that would result from having ONE MORE net use this routing  * * node.                                                                    */	    if(occ < capacity)		{		    rr_node_route_inf[inode].pres_cost = 1.;		}	    else		{		    rr_node_route_inf[inode].pres_cost =			1. + (occ + 1 - capacity) * pres_fac;		}	    if(rr_node[inode].type == SINK)		{		    tptr = tptr->next;	/* Skip next segment. */		    if(tptr == NULL)			break;		}	    tptr = tptr->next;	}			/* End while loop -- did an entire traceback. */}voidpathfinder_update_cost(float pres_fac,		       float acc_fac){/* This routine recomputes the pres_cost and acc_cost of each routing        * * resource for the pathfinder algorithm after all nets have been routed.    * * It updates the accumulated cost to by adding in the number of extra       * * signals sharing a resource right now (i.e. after each complete iteration) * * times acc_fac.  It also updates pres_cost, since pres_fac may have        * * changed.  THIS ROUTINE ASSUMES THE OCCUPANCY VALUES IN RR_NODE ARE UP TO  * * DATE.                                                                     */    int inode, occ, capacity;    for(inode = 0; inode < num_rr_nodes; inode++)	{	    occ = rr_node[inode].occ;	    capacity = rr_node[inode].capacity;	    if(occ > capacity)		{		    rr_node_route_inf[inode].acc_cost +=			(occ - capacity) * acc_fac;		    rr_node_route_inf[inode].pres_cost =			1. + (occ + 1 - capacity) * pres_fac;		}/* If occ == capacity, we don't need to increase acc_cost, but a change    * * in pres_fac could have made it necessary to recompute the cost anyway.  */	    else if(occ == capacity)		{		    rr_node_route_inf[inode].pres_cost = 1. + pres_fac;		}	}}voidinit_route_structs(int bb_factor){/* Call this before you route any nets.  It frees any old traceback and   * * sets the list of rr_nodes touched to empty.                            */    int i;    for(i = 0; i < num_nets; i++)	free_traceback(i);    load_route_bb(bb_factor);/* Check that things that should have been emptied after the last routing * * really were.                                                           */    if(rr_modified_head != NULL)	{	    printf		("Error in init_route_structs.  List of modified rr nodes is \n"		 "not empty.\n");	    exit(1);	}    if(heap_tail != 1)	{	    printf("Error in init_route_structs.  Heap is not empty.\n");	    exit(1);	}}struct s_trace *update_traceback(struct s_heap *hptr,		 int inet){/* This routine adds the most recently finished wire segment to the         * * traceback linked list.  The first connection starts with the net SOURCE  * * and begins at the structure pointed to by trace_head[inet]. Each         * * connection ends with a SINK.  After each SINK, the next connection       * * begins (if the net has more than 2 pins).  The first element after the   * * SINK gives the routing node on a previous piece of the routing, which is * * the link from the existing net to this new piece of the net.             * * In each traceback I start at the end of a path and trace back through    * * its predecessors to the beginning.  I have stored information on the     * * predecesser of each node to make traceback easy -- this sacrificies some * * memory for easier code maintenance.  This routine returns a pointer to   * * the first "new" node in the traceback (node not previously in trace).    */    struct s_trace *tptr, *prevptr, *temptail, *ret_ptr;    int inode;    short iedge;#ifdef DEBUG    t_rr_type rr_type;#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -