626 lines
21 KiB
C
626 lines
21 KiB
C
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include "util.h"
|
|
#include "vpr_types.h"
|
|
#include "globals.h"
|
|
#include "rr_graph_util.h"
|
|
#include "rr_graph.h"
|
|
#include "rr_graph2.h"
|
|
#include "rr_graph_sbox.h"
|
|
#include "check_rr_graph.h"
|
|
#include "rr_graph_timing_params.h"
|
|
#include "rr_graph_indexed_data.h"
|
|
#include "vpr_utils.h"
|
|
#include "read_xml_arch_file.h"
|
|
#include "ReadOptions.h"
|
|
#include "rr_graph_opincb.h"
|
|
|
|
/* Subroutines */
|
|
static
|
|
int add_rr_graph_one_grid_fast_edge_opin_to_cb(int grid_x,
|
|
int grid_y,
|
|
t_ivec*** LL_rr_node_indices);
|
|
|
|
static
|
|
void get_grid_side_pins(int grid_x, int grid_y,
|
|
int side, enum e_pin_type pin_type,
|
|
t_ivec*** LL_rr_node_indices,
|
|
int *num_pins, t_rr_node** *pin_list);
|
|
|
|
static
|
|
int add_opin_list_ipin_list_fast_edge(int num_opins, t_rr_node** opin_list,
|
|
int num_ipins, t_rr_node** ipin_list);
|
|
|
|
static
|
|
int add_opin_fast_edge_to_ipin(t_rr_node* opin,
|
|
t_rr_node* ipin);
|
|
|
|
static
|
|
int get_ipin_switch_index(t_rr_node* ipin);
|
|
|
|
static
|
|
void find_rr_nodes_ipin_driver_switch();
|
|
|
|
static
|
|
void recover_rr_nodes_ipin_driver_switch();
|
|
|
|
/* Xifan TANG: Create Fast Interconnection between LB OPIN and CB INPUT*/
|
|
/* TOP function */
|
|
int add_rr_graph_fast_edge_opin_to_cb(t_ivec*** LL_rr_node_indices) {
|
|
int ix, iy;
|
|
int add_edge_counter = 0;
|
|
int run_opintocb = 0;
|
|
|
|
/* Decide if we run this part */
|
|
|
|
/* For each grid, include I/O*/
|
|
for (ix = 1; ix < (nx+1); ix++) {
|
|
for (iy = 1; iy < (ny+1); iy++) {
|
|
if ((EMPTY_TYPE != grid[ix][iy].type)&&(TRUE == grid[ix][iy].type->opin_to_cb)) {
|
|
run_opintocb = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (1 == run_opintocb) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (0 == run_opintocb) {
|
|
return add_edge_counter;
|
|
}
|
|
|
|
find_rr_nodes_ipin_driver_switch();
|
|
|
|
/* For each grid, include I/O*/
|
|
for (ix = 1; ix < (nx+1); ix++) {
|
|
for (iy = 1; iy < (ny+1); iy++) {
|
|
add_edge_counter += add_rr_graph_one_grid_fast_edge_opin_to_cb(ix, iy, LL_rr_node_indices);
|
|
}
|
|
}
|
|
|
|
recover_rr_nodes_ipin_driver_switch();
|
|
|
|
return add_edge_counter;
|
|
}
|
|
|
|
/* For one grid, add fast edge from a LB OPIN to CB*/
|
|
static
|
|
int add_rr_graph_one_grid_fast_edge_opin_to_cb(int grid_x,
|
|
int grid_y,
|
|
t_ivec*** LL_rr_node_indices) {
|
|
int opin_side, ipin_side;
|
|
boolean early_stop = FALSE;
|
|
int num_opins = 0;
|
|
t_rr_node** opin_list = NULL;
|
|
int num_ipins = 0;
|
|
t_rr_node** ipin_list = NULL;
|
|
int add_edge_counter = 0;
|
|
t_type_ptr type_descriptor = NULL;
|
|
|
|
/* Make sure this is a valid grid*/
|
|
assert((-1 < grid_x) && (grid_x < (nx+1)));
|
|
assert((-1 < grid_y) && (grid_y < (ny+1)));
|
|
|
|
/* Get the type_descriptor and determine if this grid should add edges */
|
|
type_descriptor = grid[grid_x][grid_y].type;
|
|
if (NULL == type_descriptor) {
|
|
return add_edge_counter;
|
|
} else if (FALSE == type_descriptor->opin_to_cb) {
|
|
return add_edge_counter;
|
|
}
|
|
|
|
/* Check each side of this grid,
|
|
* determine how many adjacent LB should be taken into account.
|
|
*/
|
|
for (opin_side = 0; opin_side < 4; opin_side++) {
|
|
early_stop = FALSE;
|
|
switch(opin_side) {
|
|
case TOP:
|
|
/* Only I/O on the bottom side of FPGA allows to continue */
|
|
if ((0 == grid_x)||(ny + 1 == grid_y)||(nx + 1 == grid_x)) {
|
|
early_stop = TRUE;
|
|
}
|
|
break;
|
|
case RIGHT:
|
|
/* Only I/O on the left side of FPGA allows to continue */
|
|
if ((0 == grid_y)||(ny + 1 == grid_y)||(nx + 1 == grid_x)) {
|
|
early_stop = TRUE;
|
|
}
|
|
break;
|
|
case BOTTOM:
|
|
/* Only I/O on the top side of FPGA allows to continue */
|
|
if ((0 == grid_x)||(0 == grid_y)||(nx + 1 == grid_x)) {
|
|
early_stop = TRUE;
|
|
}
|
|
break;
|
|
case LEFT:
|
|
/* Only I/O on the right side of FPGA allows to continue */
|
|
if ((0 == grid_x)||(ny + 1 == grid_y)||(0 == grid_y)) {
|
|
early_stop = TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
vpr_printf(TIO_MESSAGE_ERROR, "(File: %s, [LINE%d]) Invalid opin_side(%d)!\n",
|
|
__FILE__, __LINE__, opin_side);
|
|
exit(1);
|
|
}
|
|
/* Decide if we should do something or not */
|
|
if (TRUE == early_stop) {
|
|
continue;
|
|
}
|
|
|
|
/* Find the opins on the opin_side of current grid */
|
|
get_grid_side_pins(grid_x, grid_y, opin_side, DRIVER, LL_rr_node_indices, &num_opins, &opin_list);
|
|
if (0 == num_opins) { /* Do nothing if there is no OPIN available */
|
|
continue;
|
|
}
|
|
|
|
switch(opin_side) {
|
|
case TOP:
|
|
/* Create fast connection to the grid above*/
|
|
for (ipin_side = 0; ipin_side < 4; ipin_side++) {
|
|
/* For the grid on the boundary, we only create connections to the bottom side */
|
|
if (((grid_y + 1) == (ny + 1))&&(BOTTOM != ipin_side)) {
|
|
continue;
|
|
}
|
|
/* We also skip the top side because we believe a IPIN at the top side
|
|
* can be swapped to others by using logic equivalence. Which is faster.
|
|
*/
|
|
if (TOP == ipin_side) {
|
|
continue;
|
|
}
|
|
get_grid_side_pins(grid_x, grid_y+1, ipin_side, RECEIVER, LL_rr_node_indices, &num_ipins, &ipin_list);
|
|
/* Create fast edge from the OPINs to IPINs*/
|
|
add_edge_counter += add_opin_list_ipin_list_fast_edge(num_opins, opin_list, num_ipins, ipin_list);
|
|
/* Free ipin_list */
|
|
num_ipins = 0;
|
|
free(ipin_list);
|
|
}
|
|
/* If this is already the bottom side of FPGA, we skip */
|
|
if (0 == grid_y) {
|
|
break;
|
|
}
|
|
/* Create fast connection to the grid below */
|
|
for (ipin_side = 0; ipin_side < 4; ipin_side++) {
|
|
/* For the grid on the boundary, we only create connections to the top side */
|
|
if (((grid_y - 1) == 0)&&(TOP != ipin_side)) {
|
|
continue;
|
|
}
|
|
/* We also skip the bottom side because we believe a IPIN at the bottom side
|
|
* can be swapped to others by using logic equivalence. Which is faster.
|
|
*/
|
|
if (BOTTOM == ipin_side) {
|
|
continue;
|
|
}
|
|
get_grid_side_pins(grid_x, grid_y-1, ipin_side, RECEIVER, LL_rr_node_indices, &num_ipins, &ipin_list);
|
|
/* Create fast edge from the OPINs to IPINs*/
|
|
add_edge_counter += add_opin_list_ipin_list_fast_edge(num_opins, opin_list, num_ipins, ipin_list);
|
|
/* Free ipin_list */
|
|
num_ipins = 0;
|
|
free(ipin_list);
|
|
}
|
|
break;
|
|
case RIGHT:
|
|
/* Create fast connection to the grid on the right side */
|
|
for (ipin_side = 0; ipin_side < 4; ipin_side++) {
|
|
/* For the grid on the boundary, we only create connections to the left side */
|
|
if (((grid_x + 1) == (nx + 1))&&(LEFT != ipin_side)) {
|
|
continue;
|
|
}
|
|
/* We also skip the top side because we believe a IPIN at the top side
|
|
* can be swapped to others by using logic equivalence. Which is faster.
|
|
*/
|
|
if (RIGHT == ipin_side) {
|
|
continue;
|
|
}
|
|
get_grid_side_pins(grid_x+1, grid_y, ipin_side, RECEIVER, LL_rr_node_indices, &num_ipins, &ipin_list);
|
|
/* Create fast edge from the OPINs to IPINs*/
|
|
add_edge_counter += add_opin_list_ipin_list_fast_edge(num_opins, opin_list, num_ipins, ipin_list);
|
|
/* Free ipin_list */
|
|
num_ipins = 0;
|
|
free(ipin_list);
|
|
}
|
|
/* If this is already the left side of FPGA, we skip */
|
|
if (0 == grid_x) {
|
|
break;
|
|
}
|
|
/* Create fast connection to the grid on the left side */
|
|
for (ipin_side = 0; ipin_side < 4; ipin_side++) {
|
|
/* For the grid on the boundary, we only create connections to the rigth side */
|
|
if (((grid_x - 1) == 0)&&(RIGHT != ipin_side)) {
|
|
continue;
|
|
}
|
|
/* We also skip the bottom side because we believe a IPIN at the bottom side
|
|
* can be swapped to others by using logic equivalence. Which is faster.
|
|
*/
|
|
if (LEFT == ipin_side) {
|
|
continue;
|
|
}
|
|
get_grid_side_pins(grid_x-1, grid_y, ipin_side, RECEIVER, LL_rr_node_indices, &num_ipins, &ipin_list);
|
|
/* Create fast edge from the OPINs to IPINs*/
|
|
add_edge_counter += add_opin_list_ipin_list_fast_edge(num_opins, opin_list, num_ipins, ipin_list);
|
|
/* Free ipin_list */
|
|
num_ipins = 0;
|
|
free(ipin_list);
|
|
}
|
|
break;
|
|
case BOTTOM:
|
|
/* Create fast connection to the grid on the bottom side */
|
|
for (ipin_side = 0; ipin_side < 4; ipin_side++) {
|
|
/* For the grid on the boundary, we only create connections to the left side */
|
|
if (((grid_y - 1) == 0)&&(TOP != ipin_side)) {
|
|
continue;
|
|
}
|
|
/* We also skip the top side because we believe a IPIN at the bottom side
|
|
* can be swapped to others by using logic equivalence. Which is faster.
|
|
*/
|
|
if (BOTTOM == ipin_side) {
|
|
continue;
|
|
}
|
|
get_grid_side_pins(grid_x, grid_y-1, ipin_side, RECEIVER, LL_rr_node_indices, &num_ipins, &ipin_list);
|
|
/* Create fast edge from the OPINs to IPINs*/
|
|
add_edge_counter += add_opin_list_ipin_list_fast_edge(num_opins, opin_list, num_ipins, ipin_list);
|
|
/* Free ipin_list */
|
|
num_ipins = 0;
|
|
free(ipin_list);
|
|
}
|
|
/* If this is already the left side of FPGA, we skip */
|
|
if ((ny + 1) == grid_y) {
|
|
break;
|
|
}
|
|
/* Create fast connection to the grid on the top side */
|
|
for (ipin_side = 0; ipin_side < 4; ipin_side++) {
|
|
/* For the grid on the boundary, we only create connections to the rigth side */
|
|
if (((grid_y + 1) == (ny + 1))&&(BOTTOM != ipin_side)) {
|
|
continue;
|
|
}
|
|
/* We also skip the bottom side because we believe a IPIN at the bottom side
|
|
* can be swapped to others by using logic equivalence. Which is faster.
|
|
*/
|
|
if (TOP == ipin_side) {
|
|
continue;
|
|
}
|
|
if (grid_y + 1 == ny + 1) {
|
|
assert(BOTTOM == ipin_side);
|
|
}
|
|
get_grid_side_pins(grid_x, grid_y+1, ipin_side, RECEIVER, LL_rr_node_indices, &num_ipins, &ipin_list);
|
|
/* Create fast edge from the OPINs to IPINs*/
|
|
add_edge_counter += add_opin_list_ipin_list_fast_edge(num_opins, opin_list, num_ipins, ipin_list);
|
|
/* Free ipin_list */
|
|
num_ipins = 0;
|
|
free(ipin_list);
|
|
}
|
|
break;
|
|
case LEFT:
|
|
/* Create fast connection to the grid on the left side */
|
|
for (ipin_side = 0; ipin_side < 4; ipin_side++) {
|
|
/* For the grid on the boundary, we only create connections to the left side */
|
|
if (((grid_x - 1) == 0)&&(RIGHT != ipin_side)) {
|
|
continue;
|
|
}
|
|
/* We also skip the top side because we believe a IPIN at the top side
|
|
* can be swapped to others by using logic equivalence. Which is faster.
|
|
*/
|
|
if (LEFT == ipin_side) {
|
|
continue;
|
|
}
|
|
get_grid_side_pins(grid_x-1, grid_y, ipin_side, RECEIVER, LL_rr_node_indices, &num_ipins, &ipin_list);
|
|
/* Create fast edge from the OPINs to IPINs*/
|
|
add_edge_counter += add_opin_list_ipin_list_fast_edge(num_opins, opin_list, num_ipins, ipin_list);
|
|
/* Free ipin_list */
|
|
num_ipins = 0;
|
|
free(ipin_list);
|
|
}
|
|
/* If this is already the right side of FPGA, we skip */
|
|
if ((nx + 1) == grid_x) {
|
|
break;
|
|
}
|
|
/* Create fast connection to the grid on the right side */
|
|
for (ipin_side = 0; ipin_side < 4; ipin_side++) {
|
|
/* For the grid on the boundary, we only create connections to the right side */
|
|
if (((grid_x + 1) == (nx + 1))&&(LEFT != ipin_side)) {
|
|
continue;
|
|
}
|
|
/* We also skip the bottom side because we believe a IPIN at the bottom side
|
|
* can be swapped to others by using logic equivalence. Which is faster.
|
|
*/
|
|
if (RIGHT == ipin_side) {
|
|
continue;
|
|
}
|
|
get_grid_side_pins(grid_x+1, grid_y, ipin_side, RECEIVER, LL_rr_node_indices, &num_ipins, &ipin_list);
|
|
/* Create fast edge from the OPINs to IPINs*/
|
|
add_edge_counter += add_opin_list_ipin_list_fast_edge(num_opins, opin_list, num_ipins, ipin_list);
|
|
/* Free ipin_list */
|
|
num_ipins = 0;
|
|
free(ipin_list);
|
|
}
|
|
break;
|
|
default:
|
|
vpr_printf(TIO_MESSAGE_ERROR, "(File: %s, [LINE%d]) Invalid opin_side(%d)!\n",
|
|
__FILE__, __LINE__, opin_side);
|
|
exit(1);
|
|
}
|
|
/* Free opin_list */
|
|
num_opins = 0;
|
|
free(opin_list);
|
|
}
|
|
|
|
return add_edge_counter;
|
|
}
|
|
|
|
/* Find all the OPINs at a side of one grid.
|
|
* Return num_opins, and opin_list
|
|
*/
|
|
static
|
|
void get_grid_side_pins(int grid_x, int grid_y,
|
|
int side, enum e_pin_type pin_type,
|
|
t_ivec*** LL_rr_node_indices,
|
|
int *num_pins, t_rr_node** *pin_list) {
|
|
int ipin, iheight, class_idx, cur_pin, inode;
|
|
t_type_ptr type_descriptor = NULL;
|
|
t_rr_type pin_rr_type;
|
|
|
|
switch (pin_type) {
|
|
case DRIVER:
|
|
pin_rr_type = OPIN;
|
|
break;
|
|
case RECEIVER:
|
|
pin_rr_type = IPIN;
|
|
break;
|
|
default:
|
|
vpr_printf(TIO_MESSAGE_ERROR, "(File: %s, [LINE%d]) Invalid pin_type(%d)!\n",
|
|
__FILE__, __LINE__, pin_type);
|
|
exit(1);
|
|
}
|
|
|
|
/* Initialization */
|
|
(*num_pins) = 0;
|
|
(*pin_list) = NULL;
|
|
/* (*pin_class_list) = NULL; */
|
|
|
|
/* Make sure this is a valid grid*/
|
|
assert((-1 < grid_x) && (grid_x < (nx+2)));
|
|
assert((-1 < grid_y) && (grid_y < (ny+2)));
|
|
|
|
assert((-1 < side) && (side < 4));
|
|
|
|
type_descriptor = grid[grid_x][grid_y].type;
|
|
|
|
/* Kick out corner cases */
|
|
switch(side) {
|
|
case TOP:
|
|
/* If this is the most top grid, return*/
|
|
if ((ny+1 == grid_y)||(0 == grid_x)||(nx + 1 == grid_x)) {
|
|
return;
|
|
}
|
|
break;
|
|
case RIGHT:
|
|
/* If this is the most right grid, return*/
|
|
if ((nx + 1 == grid_x)||(ny + 1 == grid_y)||(0 == grid_y)) {
|
|
return;
|
|
}
|
|
break;
|
|
case BOTTOM:
|
|
/* If this is the most bottom grid, return*/
|
|
if ((0 == grid_y)||(0 == grid_x)||(nx + 1 == grid_x)) {
|
|
return;
|
|
}
|
|
break;
|
|
case LEFT:
|
|
/* If this is the most left grid, return*/
|
|
if ((0 == grid_x)||(0 == grid_y)||(ny + 1 == grid_y)) {
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
vpr_printf(TIO_MESSAGE_ERROR, "(File: %s, [LINE%d]) Invalid side(%d)!\n",
|
|
__FILE__, __LINE__, side);
|
|
exit(1);
|
|
}
|
|
|
|
/* Count num_opins */
|
|
for (iheight = 0; iheight < type_descriptor->height; iheight++) {
|
|
for (ipin = 0; ipin < type_descriptor->num_pins; ipin++) {
|
|
/* Check if this is an OPIN at the side we want*/
|
|
class_idx = type_descriptor->pin_class[ipin];
|
|
assert((-1 < class_idx) && (class_idx < type_descriptor->num_class));
|
|
if ((1 == type_descriptor->pinloc[iheight][side][ipin])
|
|
&&(pin_type == type_descriptor->class_inf[class_idx].type)
|
|
&&(TRUE == type_descriptor->opin_to_cb)) {
|
|
(*num_pins)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Alloc array */
|
|
cur_pin = 0;
|
|
(*pin_list) = (t_rr_node**)my_malloc((*num_pins)*sizeof(t_rr_node*));
|
|
/* (*pin_class_list) = (int*)my_malloc((*num_pins)*sizeof(int)); */
|
|
|
|
/* Fill array */
|
|
for (iheight = 0; iheight < type_descriptor->height; iheight++) {
|
|
for (ipin = 0; ipin < type_descriptor->num_pins; ipin++) {
|
|
/* Check if this is an OPIN at the side we want*/
|
|
class_idx = type_descriptor->pin_class[ipin];
|
|
assert((-1 < class_idx) && (class_idx < type_descriptor->num_class));
|
|
if ((1 == type_descriptor->pinloc[iheight][side][ipin])
|
|
&&(pin_type == type_descriptor->class_inf[class_idx].type)
|
|
&&(TRUE == type_descriptor->opin_to_cb)) {
|
|
inode = get_rr_node_index(grid_x, grid_y, pin_rr_type, ipin, LL_rr_node_indices);
|
|
(*pin_list)[cur_pin] = &rr_node[inode];
|
|
/* (*pin_class_list)[cur_pin] = class_idx; */
|
|
cur_pin++;
|
|
}
|
|
}
|
|
}
|
|
assert(cur_pin == (*num_pins));
|
|
|
|
return;
|
|
}
|
|
|
|
/* We have one list of OPIN, and one list of IPIN,
|
|
* decide which two rr_nodes should have a fast edge
|
|
*/
|
|
static
|
|
int add_opin_list_ipin_list_fast_edge(int num_opins, t_rr_node** opin_list,
|
|
int num_ipins, t_rr_node** ipin_list) {
|
|
int ipin, iedge, to_node, jpin;
|
|
int num_ipin_sink = 0;
|
|
t_linked_int* ipin_sink_head = NULL;
|
|
int* ipin_sink_index = (int*)my_malloc(sizeof(int)*num_ipins);
|
|
int add_edge_counter = 0;
|
|
|
|
if (0 == num_opins) {
|
|
assert(NULL == opin_list);
|
|
return add_edge_counter;
|
|
}
|
|
|
|
if (0 == num_ipins) {
|
|
assert(NULL == ipin_list);
|
|
return add_edge_counter;
|
|
}
|
|
|
|
/* Count the number of common source of these ipin */
|
|
for (ipin = 0; ipin < num_ipins; ipin++) {
|
|
ipin_sink_index[ipin] = OPEN;
|
|
assert(IPIN == ipin_list[ipin]->type);
|
|
for (iedge = 0; iedge < ipin_list[ipin]->num_edges; iedge++) {
|
|
to_node = ipin_list[ipin]->edges[iedge];
|
|
if (SINK == rr_node[to_node].type) {
|
|
/* Search if the source exists in the list */
|
|
if (NULL == search_in_int_list(ipin_sink_head, to_node)) {
|
|
/* Do not exist, add one */
|
|
ipin_sink_head = insert_node_to_int_list(ipin_sink_head, to_node);
|
|
/* Update counter */
|
|
num_ipin_sink++;
|
|
/* Update the index list */
|
|
ipin_sink_index[ipin] = to_node;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* For each OPIN node, create a edge to each ipin whose ipin_src is different */
|
|
for (ipin = 0; ipin < num_opins; ipin++) {
|
|
for (jpin = 0; jpin < num_ipins; jpin++) {
|
|
//if (OPEN != ipin_sink_index[jpin]) {
|
|
/* Find its ipin source node*/
|
|
//ipin_sink_list_node = search_in_int_list(ipin_sink_head, ipin_sink_index[jpin]);
|
|
//if (NULL != ipin_sink_list_node) {
|
|
/* Add a fast edge */
|
|
add_edge_counter += add_opin_fast_edge_to_ipin(opin_list[ipin], ipin_list[jpin]);
|
|
/* Make the sink list node invalid */
|
|
// ipin_sink_list_node->data = OPEN;
|
|
// }
|
|
//}
|
|
}
|
|
}
|
|
|
|
/* Free */
|
|
free_int_list(&ipin_sink_head);
|
|
|
|
return add_edge_counter;
|
|
}
|
|
|
|
/* Add an edge from opin to ipin, use the switch of ipin*/
|
|
static
|
|
int add_opin_fast_edge_to_ipin(t_rr_node* opin,
|
|
t_rr_node* ipin) {
|
|
int ipin_switch_index = OPEN;
|
|
int iedge, to_node;
|
|
|
|
/* Make sure we have an OPIN and an IPIN*/
|
|
assert(OPIN == opin->type);
|
|
assert(IPIN == ipin->type);
|
|
|
|
/* Get the switch index of ipin, and check it is valid */
|
|
ipin_switch_index = get_ipin_switch_index(ipin);
|
|
if (OPEN == ipin_switch_index) {
|
|
return 0;
|
|
}
|
|
|
|
/* Check if OPIN has a fan-out to IPIN already*/
|
|
for (iedge = 0; iedge < opin->num_edges; iedge++) {
|
|
to_node = opin->edges[iedge];
|
|
if ((IPIN == rr_node[to_node].type)&&(ipin == &rr_node[to_node])) {
|
|
vpr_printf(TIO_MESSAGE_WARNING, "(File:%s,[LINE%d])OPIN rr_node[%d] has an fan-out to IPIN rr_node[%d]. Fast edge will not be created.\n", __FILE__, __LINE__, opin-rr_node, ipin-rr_node);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* create a fast edge */
|
|
/* 1. re-alloc a edge list switch list */
|
|
opin->num_edges++;
|
|
opin->edges = (int*)my_realloc(opin->edges, opin->num_edges*sizeof(int));
|
|
opin->switches = (short*)my_realloc(opin->switches, opin->num_edges*sizeof(short));
|
|
/* 2. Update edge and switch info */
|
|
opin->edges[opin->num_edges-1] = ipin - rr_node;
|
|
opin->switches[opin->num_edges-1] = ipin_switch_index;
|
|
/* 3. Increase the fan-in of IPIN */
|
|
ipin->fan_in++;
|
|
/* Finish*/
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* This is not efficent, should be improved by using LL_rr_node_indices*/
|
|
static
|
|
int get_ipin_switch_index(t_rr_node* ipin) {
|
|
return ipin->driver_switch;
|
|
}
|
|
|
|
static
|
|
void find_rr_nodes_ipin_driver_switch() {
|
|
int inode, jnode, iedge, to_node, fan_in_counter;
|
|
int ipin_switch_index = OPEN;
|
|
|
|
vpr_printf(TIO_MESSAGE_INFO, "Building rr_node driver switches...\n");
|
|
|
|
for (inode = 0; inode < num_rr_nodes; inode++) {
|
|
if (IPIN != rr_node[inode].type) {
|
|
continue;
|
|
}
|
|
/* Create a counter, check the correctness*/
|
|
fan_in_counter = 0;
|
|
ipin_switch_index = OPEN;
|
|
for (jnode = 0; jnode < num_rr_nodes; jnode++) {
|
|
for (iedge = 0; iedge < rr_node[jnode].num_edges; iedge++) {
|
|
to_node = rr_node[jnode].edges[iedge];
|
|
if (inode == to_node) {
|
|
fan_in_counter++;
|
|
if (OPEN == ipin_switch_index) {
|
|
ipin_switch_index = rr_node[jnode].switches[iedge];
|
|
} else {
|
|
assert(ipin_switch_index == rr_node[jnode].switches[iedge]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
assert(fan_in_counter == rr_node[inode].fan_in);
|
|
if (0 != fan_in_counter) {
|
|
assert(OPEN != ipin_switch_index);
|
|
}
|
|
rr_node[inode].driver_switch = ipin_switch_index;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static
|
|
void recover_rr_nodes_ipin_driver_switch() {
|
|
int inode;
|
|
|
|
vpr_printf(TIO_MESSAGE_INFO, "Recovering rr_node driver switches...\n");
|
|
|
|
for (inode = 0; inode < num_rr_nodes; inode++) {
|
|
if (IPIN == rr_node[inode].type) {
|
|
rr_node[inode].driver_switch = OPEN;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|