|
VPR-6.0
|
#include <assert.h>#include "util.h"#include "vpr_types.h"#include "globals.h"#include "rr_graph.h"#include "rr_graph_util.h"#include "rr_graph2.h"#include "rr_graph_timing_params.h"
Include dependency graph for rr_graph_timing_params.c:Go to the source code of this file.
Functions | |
| void | add_rr_graph_C_from_switches (float C_ipin_cblock) |
| void add_rr_graph_C_from_switches | ( | float | C_ipin_cblock | ) |
This routine finishes loading the C elements of the rr_graph. It assumes that when you call it the CHANX and CHANY nodes have had their C set to their metal capacitance, and everything else has C set to 0. The graph connectivity (edges, switch types etc.) must all be loaded too. This routine will add in the capacitance on the CHANX and CHANY nodes due to:
Definition at line 27 of file rr_graph_timing_params.c.
{
int inode, iedge, switch_index, to_node, maxlen;
int icblock, isblock, iseg_low, iseg_high;
float Cin, Cout;
t_rr_type from_rr_type, to_rr_type;
boolean *cblock_counted; /* [0..max(nx,ny)] -- 0th element unused. */
float *buffer_Cin; /* [0..max(nx,ny)] */
boolean buffered;
float *Couts_to_add; /* UDSD */
maxlen = max(nx, ny) + 1;
cblock_counted = (boolean *) my_calloc(maxlen, sizeof(boolean));
buffer_Cin = (float *)my_calloc(maxlen, sizeof(float));
for(inode = 0; inode < num_rr_nodes; inode++)
{
from_rr_type = rr_node[inode].type;
if(from_rr_type == CHANX || from_rr_type == CHANY)
{
for(iedge = 0; iedge < rr_node[inode].num_edges; iedge++)
{
to_node = rr_node[inode].edges[iedge];
to_rr_type = rr_node[to_node].type;
if(to_rr_type == CHANX || to_rr_type == CHANY)
{
switch_index =
rr_node[inode].switches[iedge];
Cin = switch_inf[switch_index].Cin;
Cout = switch_inf[switch_index].Cout;
buffered =
switch_inf[switch_index].buffered;
/* If both the switch from inode to to_node and the switch from *
* to_node back to inode use bidirectional switches (i.e. pass *
* transistors), there will only be one physical switch for *
* both edges. Hence, I only want to count the capacitance of *
* that switch for one of the two edges. (Note: if there is *
* a pass transistor edge from x to y, I always build the graph *
* so that there is a corresponding edge using the same switch *
* type from y to x.) So, I arbitrarily choose to add in the *
* capacitance in that case of a pass transistor only when *
* processing the the lower inode number. *
* If an edge uses a buffer I always have to add in the output *
* capacitance. I assume that buffers are shared at the same *
* (i,j) location, so only one input capacitance needs to be *
* added for all the buffered switches at that location. If *
* the buffers at that location have different sizes, I use the *
* input capacitance of the largest one. */
if(!buffered && inode < to_node)
{ /* Pass transistor. */
rr_node[inode].C += Cin;
rr_node[to_node].C += Cout;
}
else if(buffered)
{
/* Prevent double counting of capacitance for UDSD */
if(rr_node[to_node].drivers !=
SINGLE)
{
/* For multiple-driver architectures the output capacitance can
* be added now since each edge is actually a driver */
rr_node[to_node].C +=
Cout;
}
isblock =
seg_index_of_sblock(inode,
to_node);
buffer_Cin[isblock] =
max(buffer_Cin[isblock], Cin);
}
}
/* End edge to CHANX or CHANY node. */
else if(to_rr_type == IPIN)
{
/* Code below implements sharing of the track to connection *
* box buffer. I assume there is one such buffer at every *
* segment of the wire at which at least one logic block input *
* connects. */
icblock =
seg_index_of_cblock(from_rr_type,
to_node);
if(cblock_counted[icblock] == FALSE)
{
rr_node[inode].C += C_ipin_cblock;
cblock_counted[icblock] = TRUE;
}
}
} /* End loop over all edges of a node. */
/* Reset the cblock_counted and buffer_Cin arrays, and add buf Cin. */
/* Method below would be faster for very unpopulated segments, but I *
* think it would be slower overall for most FPGAs, so commented out. */
/* for (iedge=0;iedge<rr_node[inode].num_edges;iedge++) {
* to_node = rr_node[inode].edges[iedge];
* if (rr_node[to_node].type == IPIN) {
* icblock = seg_index_of_cblock (from_rr_type, to_node);
* cblock_counted[icblock] = FALSE;
* }
* } */
if(from_rr_type == CHANX)
{
iseg_low = rr_node[inode].xlow;
iseg_high = rr_node[inode].xhigh;
}
else
{ /* CHANY */
iseg_low = rr_node[inode].ylow;
iseg_high = rr_node[inode].yhigh;
}
for(icblock = iseg_low; icblock <= iseg_high; icblock++)
{
cblock_counted[icblock] = FALSE;
}
for(isblock = iseg_low - 1; isblock <= iseg_high;
isblock++)
{
rr_node[inode].C += buffer_Cin[isblock]; /* Biggest buf Cin at loc */
buffer_Cin[isblock] = 0.;
}
}
/* End node is CHANX or CHANY */
else if(from_rr_type == OPIN)
{
for(iedge = 0; iedge < rr_node[inode].num_edges; iedge++)
{
switch_index = rr_node[inode].switches[iedge];
/* UDSD by ICK Start */
to_node = rr_node[inode].edges[iedge];
to_rr_type = rr_node[to_node].type;
assert(to_rr_type == CHANX
|| to_rr_type == CHANY);
if(rr_node[to_node].drivers != SINGLE)
{
Cout = switch_inf[switch_index].Cout;
to_node = rr_node[inode].edges[iedge]; /* Will be CHANX or CHANY */
rr_node[to_node].C += Cout;
}
}
}
/* End node is OPIN. */
} /* End for all nodes. */
/* Now we need to add any cout loads for nets that we previously didn't process
* Current structures only keep switch information from a node to the next node and
* not the reverse. Therefore I need to go through all the possible edges to figure
* out what the Cout's should be */
Couts_to_add = (float *)my_calloc(num_rr_nodes, sizeof(float));
for(inode = 0; inode < num_rr_nodes; inode++)
{
for(iedge = 0; iedge < rr_node[inode].num_edges; iedge++)
{
switch_index = rr_node[inode].switches[iedge];
to_node = rr_node[inode].edges[iedge];
to_rr_type = rr_node[to_node].type;
if(to_rr_type == CHANX || to_rr_type == CHANY)
{
if(rr_node[to_node].drivers == SINGLE)
{
/* Cout was not added in these cases */
if(Couts_to_add[to_node] != 0)
{
/* We've already found a Cout to add to this node
* We could take the max of all possibilities but
* instead I will fail if there are conflicting Couts */
if(Couts_to_add[to_node] !=
switch_inf[switch_index].Cout)
{
printf
("Error: A single driver resource (%i) is driven by different Cout's (%e!=%e)\n",
to_node,
Couts_to_add
[to_node],
switch_inf
[switch_index].Cout);
exit(1);
}
}
Couts_to_add[to_node] =
switch_inf[switch_index].Cout;
}
}
}
}
for(inode = 0; inode < num_rr_nodes; inode++)
{
rr_node[inode].C += Couts_to_add[inode];
}
free(Couts_to_add);
free(cblock_counted);
free(buffer_Cin);
}
Here is the call graph for this function:
Here is the caller graph for this function: