Пример #1
0
static void
directed_search_add_source_to_heap(int inet,
				   int target_node,
				   float astar_fac)
{

/* Adds the SOURCE of this net to the heap.  Used to start a net's routing. */

    int inode;
    float back_cost, tot_cost;

    inode = net_rr_terminals[inet][0];	/* SOURCE */
    back_cost = 0.0 + get_rr_cong_cost(inode);

    /* setting the total cost to 0 because it's the only element on the heap */
    if(!is_empty_heap())
	{
	    printf
		("Error: Wrong Assumption: in directed_search_add_source_to_heap "
		 "the heap is not empty. Need to properly calculate source node's cost.\n");
	    exit(1);
	}

    /* WMF: path cost is 0. could use tot_cost = 0 to save some computation time, but
     * for consistency, I chose to do the expected cost calculation. */
    tot_cost =
	back_cost + astar_fac * get_directed_search_expected_cost(inode,
								  target_node);
    node_to_heap(inode, tot_cost, NO_PREVIOUS, NO_PREVIOUS, back_cost, OPEN);

}
Пример #2
0
static void breadth_first_expand_neighbours (int inode, float pcost, int inet,
          float bend_cost) {

/* Puts all the rr_nodes adjacent to inode on the heap.  rr_nodes outside   *
 * the expanded bounding box specified in route_bb are not added to the     *
 * heap.  pcost is the path_cost to get to inode.                           */

 int iconn, to_node, num_edges;
 t_rr_type from_type, to_type;
 float tot_cost;

 num_edges = rr_node[inode].num_edges;
 for (iconn=0;iconn<num_edges;iconn++) {
    to_node = rr_node[inode].edges[iconn];

    if (   rr_node[to_node].xhigh < route_bb[inet].xmin ||
           rr_node[to_node].xlow > route_bb[inet].xmax  ||
           rr_node[to_node].yhigh < route_bb[inet].ymin ||
           rr_node[to_node].ylow > route_bb[inet].ymax    )
       continue;      /* Node is outside (expanded) bounding box. */

    tot_cost = pcost + get_rr_cong_cost (to_node);

    if (bend_cost != 0.) {
       from_type = rr_node[inode].type;
       to_type = rr_node[to_node].type;
       if ((from_type == CHANX && to_type == CHANY) ||
              (from_type == CHANY && to_type == CHANX))
          tot_cost += bend_cost;
    }

    node_to_heap (to_node, tot_cost, inode, iconn, OPEN, OPEN);
 }
}
Пример #3
0
void reserve_locally_used_opins (float pres_fac, boolean rip_up_local_opins,
          t_ivec **clb_opins_used_locally) {

/* If some subblock outputs are hooked directly to CLB outputs, then      *
 * some CLB outputs are occupied if their associated subblock is used     *
 * locally, even though the inter-CLB netlist does not say those outputs  *
 * have to connect to anything.  This is important when you have          *
 * logically equivalent outputs.  Code below makes sure any CLB outputs   *
 * that are used by being directly hooked to subblocks get properly       *
 * reserved.                                                              */

 int iblk, num_local_opin, inode, from_node, iconn, num_edges, to_node;
 int iclass, ipin;
 float cost;
 struct s_heap *heap_head_ptr;

 if (rip_up_local_opins) {
    for (iblk=0;iblk<num_blocks;iblk++) {
       for (iclass=0;iclass<num_class;iclass++) {
          num_local_opin = clb_opins_used_locally[iblk][iclass].nelem; 
                  /* Always 0 for pads and for RECEIVER (IPIN) classes */
          for (ipin=0;ipin<num_local_opin;ipin++) {
             inode = clb_opins_used_locally[iblk][iclass].list[ipin];
             adjust_one_rr_occ_and_pcost (inode, -1, pres_fac);
          }
       }
    }
 }     
 
 for (iblk=0;iblk<num_blocks;iblk++) {
    for (iclass=0;iclass<num_class;iclass++) {
       num_local_opin = clb_opins_used_locally[iblk][iclass].nelem; 
               /* Always 0 for pads and for RECEIVER (IPIN) classes */

       if (num_local_opin != 0) {  /* Have to reserve (use) some OPINs */
          from_node = rr_clb_source[iblk][iclass];
          num_edges = rr_node[from_node].num_edges;
          for (iconn=0;iconn<num_edges;iconn++) {
             to_node = rr_node[from_node].edges[iconn];
             cost = get_rr_cong_cost (to_node);
             node_to_heap (to_node, cost, OPEN, OPEN, 0., 0.);
          }

          for (ipin=0;ipin<num_local_opin;ipin++) {
             heap_head_ptr = get_heap_head ();
             inode = heap_head_ptr->index;
             adjust_one_rr_occ_and_pcost (inode, 1, pres_fac);
             clb_opins_used_locally[iblk][iclass].list[ipin] = inode;
             free_heap_data (heap_head_ptr);
          }

          empty_heap ();
       }
    }
 }
}
Пример #4
0
static void breadth_first_add_source_to_heap (int inet) {

/* Adds the SOURCE of this net to the heap.  Used to start a net's routing. */

 int inode;
 float cost;

 inode = net_rr_terminals[inet][0];   /* SOURCE */
 cost = get_rr_cong_cost (inode);

 node_to_heap (inode, cost, NO_PREVIOUS, NO_PREVIOUS, OPEN, OPEN);
}
Пример #5
0
/**
 * Adapted from breadth_first_add_source_to_heap() 
 */
static void inc_breadth_first_add_inode_to_heap(int inode)
{
	float cost;
	cost = get_rr_cong_cost(inode);
	node_to_heap(inode, cost, NO_PREVIOUS, NO_PREVIOUS, OPEN, OPEN);
}
Пример #6
0
static void breadth_first_expand_trace_segment (struct s_trace *start_ptr,
        int remaining_connections_to_sink) {
 
/* Adds all the rr_nodes in the traceback segment starting at tptr (and     *
 * continuing to the end of the traceback) to the heap with a cost of zero. *
 * This allows expansion to begin from the existing wiring.  The            *
 * remaining_connections_to_sink value is 0 if the route segment ending     *
 * at this location is the last one to connect to the SINK ending the route *
 * segment.  This is the usual case.  If it is not the last connection this *
 * net must make to this SINK, I have a hack to ensure the next connection  *
 * to this SINK goes through a different IPIN.  Without this hack, the      *
 * router would always put all the connections from this net to this SINK   *
 * through the same IPIN.  With LUTs or cluster-based logic blocks, you     *
 * should never have a net connecting to two logically-equivalent pins on   *
 * the same logic block, so the hack will never execute.  If your logic     *
 * block is an and-gate, however, nets might connect to two and-inputs on   *
 * the same logic block, and since the and-inputs are logically-equivalent, *
 * this means two connections to the same SINK.                             */

 struct s_trace *tptr, *next_ptr;
 int inode, sink_node, last_ipin_node;

 tptr = start_ptr;

 if (remaining_connections_to_sink == 0) {   /* Usual case. */
    while (tptr != NULL) {
       node_to_heap (tptr->index, 0., NO_PREVIOUS, NO_PREVIOUS, OPEN, OPEN);
       tptr = tptr->next;
    }
 }

 else {   /* This case never executes for most logic blocks. */

/* Weird case.  Lots of hacks. The cleanest way to do this would be to empty *
 * the heap, update the congestion due to the partially-completed route, put *
 * the whole route so far (excluding IPINs and SINKs) on the heap with cost  *
 * 0., and expand till you hit the next SINK.  That would be slow, so I      *
 * do some hacks to enable incremental wavefront expansion instead.          */

    if (tptr == NULL)
       return;         /* No route yet */

    next_ptr = tptr->next;
    last_ipin_node = OPEN;  /* Stops compiler from complaining. */

/* Can't put last SINK on heap with NO_PREVIOUS, etc, since that won't let  *
 * us reach it again.  Instead, leave the last traceback element (SINK) off *
 * the heap.                                                                */

    while (next_ptr != NULL) {
       inode = tptr->index;
       node_to_heap (inode, 0., NO_PREVIOUS, NO_PREVIOUS, OPEN, OPEN);
 
       if (rr_node[inode].type == IPIN)
          last_ipin_node = inode;
 
       tptr = next_ptr;
       next_ptr = tptr->next;
    }
 
/* This will stop the IPIN node used to get to this SINK from being         *
 * reexpanded for the remainder of this net's routing.  This will make us   *
 * hook up more IPINs to this SINK (which is what we want).  If IPIN        *
 * doglegs are allowed in the graph, we won't be able to use this IPIN to   *
 * do a dogleg, since it won't be re-expanded.  Shouldn't be a big problem. */

    rr_node_route_inf[last_ipin_node].path_cost = - HUGE_FLOAT;

/* Also need to mark the SINK as having high cost, so another connection can *
 * be made to it.                                                            */

    sink_node = tptr->index;
    rr_node_route_inf[sink_node].path_cost = HUGE_FLOAT;

/* Finally, I need to remove any pending connections to this SINK via the    *
 * IPIN I just used (since they would result in congestion).  Scan through   *
 * the heap to do this.                                                      */

    invalidate_heap_entries (sink_node, last_ipin_node);
 }
}
Пример #7
0
static void
directed_search_expand_neighbours(struct s_heap *current,
				  int inet,
				  float bend_cost,
				  int target_node,
				  int highfanout_rlim,
				  float astar_fac)
{

/* Puts all the rr_nodes adjacent to current on the heap.  rr_nodes outside   *
 * the expanded bounding box specified in route_bb are not added to the     *
 * heap.  back_cost is the path_cost to get to inode. total cost i.e.
 * tot_cost is path_cost + (expected_cost to target sink) */

    int iconn, to_node, num_edges, inode, target_x, target_y;
    t_rr_type from_type, to_type;
    float new_tot_cost, old_back_pcost, new_back_pcost;

    inode = current->index;
    old_back_pcost = current->backward_path_cost;
    num_edges = rr_node[inode].num_edges;

    target_x = rr_node[target_node].xhigh;
    target_y = rr_node[target_node].yhigh;

    for(iconn = 0; iconn < num_edges; iconn++)
	{
	    to_node = rr_node[inode].edges[iconn];

	    if(rr_node[to_node].xhigh < route_bb[inet].xmin ||
	       rr_node[to_node].xlow > route_bb[inet].xmax ||
	       rr_node[to_node].yhigh < route_bb[inet].ymin ||
	       rr_node[to_node].ylow > route_bb[inet].ymax)
		continue;	/* Node is outside (expanded) bounding box. */

		if(clb_net[inet].num_sinks >= HIGH_FANOUT_NET_LIM) {
			if(rr_node[to_node].xhigh < target_x - highfanout_rlim ||
				rr_node[to_node].xlow > target_x + highfanout_rlim ||
				rr_node[to_node].yhigh < target_y - highfanout_rlim ||
				rr_node[to_node].ylow > target_y + highfanout_rlim)
			continue;	/* Node is outside high fanout bin. */
		}

/* Prune away IPINs that lead to blocks other than the target one.  Avoids  *
 * the issue of how to cost them properly so they don't get expanded before *
 * more promising routes, but makes route-throughs (via CLBs) impossible.   *
 * Change this if you want to investigate route-throughs.                   */

	    to_type = rr_node[to_node].type;
	    if(to_type == IPIN && (rr_node[to_node].xhigh != target_x ||
				   rr_node[to_node].yhigh != target_y))
		continue;

/* new_back_pcost stores the "known" part of the cost to this node -- the   *
 * congestion cost of all the routing resources back to the existing route  *
 * new_tot_cost 
 * is this "known" backward cost + an expected cost to get to the target.   */

	    new_back_pcost = old_back_pcost + get_rr_cong_cost(to_node);

	    if(bend_cost != 0.)
		{
		    from_type = rr_node[inode].type;
		    to_type = rr_node[to_node].type;
		    if((from_type == CHANX && to_type == CHANY) ||
		       (from_type == CHANY && to_type == CHANX))
			new_back_pcost += bend_cost;
		}

	    /* Calculate the new total cost = path cost + astar_fac * remaining distance to target */
	    new_tot_cost = new_back_pcost + astar_fac *
		get_directed_search_expected_cost(to_node, target_node);

	    node_to_heap(to_node, new_tot_cost, inode, iconn, new_back_pcost,
			 OPEN);
	}
}
Пример #8
0
static int
directed_search_expand_trace_segment(struct s_trace *start_ptr,
				     int target_node,
				     float astar_fac,
					 int inet,
				     int remaining_connections_to_sink)
{

/* Adds all the rr_nodes in the entire traceback from SOURCE to all SINKS   *
 * routed so far (partial routing). 
 * This allows expansion to begin from the existing wiring.  The            *
 * remaining_connections_to_sink value is 0 if the route segment ending     *
 * at this location is the last one to connect to the SINK ending the route *
 * segment.  This is the usual case.  If it is not the last connection this *
 * net must make to this SINK, I have a hack to ensure the next connection  *
 * to this SINK goes through a different IPIN.  Without this hack, the      *
 * router would always put all the connections from this net to this SINK   *
 * through the same IPIN.  With LUTs or cluster-based logic blocks, you     *
 * should never have a net connecting to two logically-equivalent pins on   *
 * the same logic block, so the hack will never execute.  If your logic     *
 * block is an and-gate, however, nets might connect to two and-inputs on   *
 * the same logic block, and since the and-inputs are logically-equivalent, *
 * this means two connections to the same SINK.                             *
 *                                                                          *
 * For high-fanout nets, return the radius of the expansion bin,            *
 * undefined otherwise                                                      */

    struct s_trace *tptr;
    int inode, backward_path_cost, tot_cost;
	int target_x, target_y;
	int rlim, area;
	boolean success;

	target_x = rr_node[target_node].xhigh;
    target_y = rr_node[target_node].yhigh;

	area = (route_bb[inet].xmax - route_bb[inet].xmin) * (route_bb[inet].ymax - route_bb[inet].ymin);
	if(area <= 0) {
		area = 1;
	}
	
	if(clb_net[inet].num_sinks < HIGH_FANOUT_NET_LIM) {
		rlim = 1;
	} else {
		rlim = ceil(sqrt((float)area / (float)clb_net[inet].num_sinks));
		if(start_ptr == NULL) {
			/* For first node, route normally since there is nothing in the current traceback path */
			rlim = max(nx + 2, ny + 2);
		}
	}
	success = FALSE;
	/* determine quickly a feasible bin radius to route sink for high fanout nets 
	   this is necessary to prevent super long runtimes for high fanout nets; in best case, a reduction in complexity from O(N^2logN) to O(NlogN) (Swartz fast router)
	*/
	while(success == FALSE && start_ptr != NULL) {
		tptr = start_ptr;
		while(tptr != NULL && success == FALSE)
		{
			inode = tptr->index;
			if(!(rr_node[inode].type == IPIN || rr_node[inode].type == SINK)) {
				if( clb_net[inet].num_sinks < HIGH_FANOUT_NET_LIM ||
					(rr_node[inode].xlow <= target_x + rlim &&
					rr_node[inode].xhigh >= target_x - rlim &&
					rr_node[inode].ylow <= target_y + rlim &&
					rr_node[inode].yhigh >= target_y - rlim)) {
					success = TRUE;
				}
			}
			tptr = tptr->next;
		}
		
		if(success == FALSE) {
			if(rlim > max(nx + 2, ny + 2)) { 
				printf(ERRTAG "VPR internal error, net %s has paths that are not found in traceback\n", clb_net[inet].name);
				exit(1);
			}
			/* if sink not in bin, increase bin size until fit */
			rlim *= 2;
		} else {
			/* Sometimes might just catch a wire in the end segment, need to give it some channel space to explore */
			rlim += 4;
		}
	}

	if(remaining_connections_to_sink == 0)
	{			/* Usual case. */
		tptr = start_ptr;
		while(tptr != NULL)
		{
			/* WMF: partial routing is added to the heap with path cost of 0, because
			 * new extension to the next sink can start at any point on current partial 
			 * routing. However, for directed search the total cost must be made to favor
			 * the points of current partial routing that are NEAR the next sink (target sink) */

			/* WMF: IPINs and SINKs should be excluded from the heap in this
			 * since they NEVER connect TO any rr_node (no to_edges), but since they have
			 * no to_edges, it's ok (ROUTE_THROUGHS are disabled). To clarify, see 
			 * rr_graph.c to find out rr_node[inode].num_edges = 0 for SINKs and
			 * rr_node[inode].num_edges = 1 for INPINs */

			inode = tptr->index;
			if(!
			   (rr_node[inode].type == IPIN
			|| rr_node[inode].type == SINK))
			{
				if( clb_net[inet].num_sinks < HIGH_FANOUT_NET_LIM ||
					(rr_node[inode].xlow <= target_x + rlim &&
					rr_node[inode].xhigh >= target_x - rlim &&
					rr_node[inode].ylow <= target_y + rlim &&
					rr_node[inode].yhigh >= target_y - rlim)) {
					backward_path_cost = 0;
					tot_cost =
					backward_path_cost +
					astar_fac *
					get_directed_search_expected_cost(inode,
									  target_node);
					node_to_heap(inode, tot_cost, NO_PREVIOUS,
						 NO_PREVIOUS, backward_path_cost,
						 OPEN);
				}
			}

			tptr = tptr->next;
		}
	}
	else
	{			/* This case never executes for most logic blocks. */
		printf("Warning: Multiple connections from net to the same sink. "
		   "This should not happen for LUT/Cluster based logic blocks. Aborting.\n");
		exit(1);
	}
	return rlim;
}
Пример #9
0
static void
directed_search_expand_trace_segment(struct s_trace *start_ptr,
				     int target_node,
				     float astar_fac,
				     int remaining_connections_to_sink)
{

/* Adds all the rr_nodes in the entire traceback from SOURCE to all SINKS   *
 * routed so far (partial routing). 
 * This allows expansion to begin from the existing wiring.  The            *
 * remaining_connections_to_sink value is 0 if the route segment ending     *
 * at this location is the last one to connect to the SINK ending the route *
 * segment.  This is the usual case.  If it is not the last connection this *
 * net must make to this SINK, I have a hack to ensure the next connection  *
 * to this SINK goes through a different IPIN.  Without this hack, the      *
 * router would always put all the connections from this net to this SINK   *
 * through the same IPIN.  With LUTs or cluster-based logic blocks, you     *
 * should never have a net connecting to two logically-equivalent pins on   *
 * the same logic block, so the hack will never execute.  If your logic     *
 * block is an and-gate, however, nets might connect to two and-inputs on   *
 * the same logic block, and since the and-inputs are logically-equivalent, *
 * this means two connections to the same SINK.                             */

    struct s_trace *tptr;
    int inode, backward_path_cost, tot_cost;

    tptr = start_ptr;

    if(remaining_connections_to_sink == 0)
	{			/* Usual case. */
	    while(tptr != NULL)
		{
		    /* WMF: partial routing is added to the heap with path cost of 0, because
		     * new extension to the next sink can start at any point on current partial 
		     * routing. However, for directed search the total cost must be made to favor
		     * the points of current partial routing that are NEAR the next sink (target sink) */

		    /* WMF: IPINs and SINKs should be excluded from the heap in this
		     * since they NEVER connect TO any rr_node (no to_edges), but since they have
		     * no to_edges, it's ok (ROUTE_THROUGHS are disabled). To clarify, see 
		     * rr_graph.c to find out rr_node[inode].num_edges = 0 for SINKs and
		     * rr_node[inode].num_edges = 1 for INPINs */

		    inode = tptr->index;

		    if(!
		       (rr_node[inode].type == IPIN
			|| rr_node[inode].type == SINK))
			{

			    backward_path_cost = 0;
			    tot_cost =
				backward_path_cost +
				astar_fac *
				get_directed_search_expected_cost(inode,
								  target_node);
			    node_to_heap(inode, tot_cost, NO_PREVIOUS,
					 NO_PREVIOUS, backward_path_cost,
					 OPEN);
			}

		    tptr = tptr->next;
		}
	}

    else
	{			/* This case never executes for most logic blocks. */
	    printf("Warning: Multiple connections from net to the same sink. "
		   "This should not happen for LUT/Cluster based logic blocks. Aborting.\n");
	    exit(1);
	}
}