1066 lines
34 KiB
C
Executable File
1066 lines
34 KiB
C
Executable File
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include "util.h"
|
|
#include "vpr_types.h"
|
|
#include "globals.h"
|
|
#include "route_common.h"
|
|
#include "place_and_route.h"
|
|
#include "route_tree_timing.h"
|
|
#include "route_timing.h"
|
|
#include "timing_place_lookup.h"
|
|
#include "rr_graph.h"
|
|
#include "route_export.h"
|
|
#include <assert.h>
|
|
#include "read_xml_arch_file.h"
|
|
|
|
/* mrFPGA : Xifan TANG */
|
|
#include "mrfpga_globals.h"
|
|
#include "net_delay_types.h"
|
|
#include "net_delay_local_void.h"
|
|
/* end */
|
|
|
|
/*this file contains routines that generate the array containing*/
|
|
/*the delays between blocks, this is used in the timing driven */
|
|
/*placement routines */
|
|
|
|
/*To compute delay between blocks we place temporary blocks at */
|
|
/*different locations in the FPGA and route nets between */
|
|
/*the blocks. From this procedure we generate a lookup table */
|
|
/*which tells us the delay between different locations in */
|
|
/*the FPGA */
|
|
|
|
/*Note: these routines assume that there is a uniform and even */
|
|
/*distribution of the different wire segments. If this is not */
|
|
/*the case, then this lookup table will be off */
|
|
|
|
/*Note: This code removes all heterogeneous types and creates an
|
|
artificial 1x1 tile. A good lookup for heterogeniety
|
|
requires more research */
|
|
|
|
#define NET_COUNT 1 /*we only use one net in these routines, */
|
|
/*it is repeatedly routed and ripped up */
|
|
/*to compute delays between different */
|
|
/*locations, this value should not change */
|
|
#define NET_USED 0 /*we use net at location zero of the net */
|
|
/*structure */
|
|
#define NET_USED_SOURCE_BLOCK 0 /*net.block[0] is source block */
|
|
#define NET_USED_SINK_BLOCK 1 /*net.block[1] is sink block */
|
|
#define SOURCE_BLOCK 0 /*block[0] is source */
|
|
#define SINK_BLOCK 1 /*block[1] is sink */
|
|
|
|
#define BLOCK_COUNT 2 /*use 2 blocks to compute delay between */
|
|
/*the various FPGA locations */
|
|
/*do not change this number unless you */
|
|
/*really know what you are doing, it is */
|
|
/*assumed that the net only connects to */
|
|
/*two blocks */
|
|
|
|
#define NUM_TYPES_USED 3 /* number of types used in look up */
|
|
|
|
#define DEBUG_TIMING_PLACE_LOOKUP /*initialize arrays to known state */
|
|
|
|
#define DUMPFILE "lookup_dump.echo"
|
|
/* #define PRINT_ARRAYS *//*only used during debugging, calls routine to */
|
|
/*print out the various lookup arrays */
|
|
|
|
/***variables that are exported to other modules***/
|
|
|
|
/*the delta arrays are used to contain the best case routing delay */
|
|
/*between different locations on the FPGA. */
|
|
|
|
float **delta_io_to_clb;
|
|
float **delta_clb_to_clb;
|
|
float **delta_clb_to_io;
|
|
float **delta_io_to_io;
|
|
|
|
/*** Other Global Arrays ******/
|
|
/* I could have allocated these as local variables, and passed them all */
|
|
/* around, but was too lazy, since this is a small file, it should not */
|
|
/* be a big problem */
|
|
|
|
static float **net_delay;
|
|
static float *pin_criticality;
|
|
static int *sink_order;
|
|
static t_rt_node **rt_node_of_sink;
|
|
static t_type_ptr IO_TYPE_BACKUP;
|
|
static t_type_ptr EMPTY_TYPE_BACKUP;
|
|
static t_type_ptr FILL_TYPE_BACKUP;
|
|
static t_type_descriptor dummy_type_descriptors[NUM_TYPES_USED];
|
|
static t_type_descriptor *type_descriptors_backup;
|
|
static struct s_grid_tile **grid_backup;
|
|
static int num_types_backup;
|
|
|
|
static t_ivec **clb_opins_used_locally;
|
|
|
|
#ifdef PRINT_ARRAYS
|
|
static FILE *lookup_dump; /* If debugging mode is on, print out to
|
|
* the file defined in DUMPFILE */
|
|
#endif /* PRINT_ARRAYS */
|
|
|
|
/*** Function Prototypes *****/
|
|
|
|
static void alloc_net(void);
|
|
|
|
static void alloc_block(void);
|
|
|
|
static void load_simplified_device(void);
|
|
static void restore_original_device(void);
|
|
|
|
static void alloc_and_assign_internal_structures(struct s_net **original_net,
|
|
struct s_block **original_block, int *original_num_nets,
|
|
int *original_num_blocks);
|
|
|
|
static void free_and_reset_internal_structures(struct s_net *original_net,
|
|
struct s_block *original_block, int original_num_nets,
|
|
int original_num_blocks);
|
|
|
|
static void setup_chan_width(struct s_router_opts router_opts,
|
|
t_chan_width_dist chan_width_dist);
|
|
|
|
static void alloc_routing_structs(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf, INP t_direct_inf *directs,
|
|
INP int num_directs);
|
|
|
|
static void free_routing_structs(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf);
|
|
|
|
static void assign_locations(t_type_ptr source_type, int source_x_loc,
|
|
int source_y_loc, int source_z_loc, t_type_ptr sink_type,
|
|
int sink_x_loc, int sink_y_loc, int sink_z_loc);
|
|
|
|
static float assign_blocks_and_route_net(t_type_ptr source_type,
|
|
int source_x_loc, int source_y_loc, t_type_ptr sink_type,
|
|
int sink_x_loc, int sink_y_loc, struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf);
|
|
|
|
static void alloc_delta_arrays(void);
|
|
|
|
static void free_delta_arrays(void);
|
|
|
|
static void generic_compute_matrix(float ***matrix_ptr, t_type_ptr source_type,
|
|
t_type_ptr sink_type, int source_x, int source_y, int start_x,
|
|
int end_x, int start_y, int end_y, struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf);
|
|
|
|
static void compute_delta_clb_to_clb(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf, int longest_length);
|
|
|
|
static void compute_delta_io_to_clb(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf);
|
|
|
|
static void compute_delta_clb_to_io(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf);
|
|
|
|
static void compute_delta_io_to_io(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf);
|
|
|
|
static void compute_delta_arrays(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf, int longest_length);
|
|
|
|
static int get_first_pin(enum e_pin_type pintype, t_type_ptr type);
|
|
|
|
static int get_longest_segment_length(
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf);
|
|
static void reset_placement(void);
|
|
|
|
/* mrFPGA: Xifan TANG */
|
|
void try_buffer_for_net( int inet, t_rc_node** rc_node_free_list, t_linked_rc_edge** rc_edge_free_list, t_linked_rc_ptr* rr_node_to_rc_node, float* net_delay );
|
|
|
|
static void buffer_net(float* cur_net_delay);
|
|
/* end */
|
|
|
|
#ifdef PRINT_ARRAYS
|
|
static void print_array(float **array_to_print,
|
|
int x1,
|
|
int x2,
|
|
int y1,
|
|
int y2);
|
|
#endif
|
|
/**************************************/
|
|
static int get_first_pin(enum e_pin_type pintype, t_type_ptr type) {
|
|
|
|
/*this code assumes logical equivilance between all driving pins */
|
|
/*global pins are not hooked up to the temporary net */
|
|
|
|
int i, currpin;
|
|
|
|
currpin = 0;
|
|
for (i = 0; i < type->num_class; i++) {
|
|
if (type->class_inf[i].type == pintype && !type->is_global_pin[currpin])
|
|
return (type->class_inf[i].pinlist[0]);
|
|
else
|
|
currpin += type->class_inf[i].num_pins;
|
|
}
|
|
assert(0);
|
|
exit(0); /*should never hit this line */
|
|
}
|
|
|
|
/**************************************/
|
|
static int get_longest_segment_length(
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf) {
|
|
|
|
int i, length;
|
|
|
|
length = 0;
|
|
for (i = 0; i < det_routing_arch.num_segment; i++) {
|
|
if (segment_inf[i].length > length)
|
|
length = segment_inf[i].length;
|
|
}
|
|
return (length);
|
|
}
|
|
|
|
/**************************************/
|
|
static void alloc_net(void) {
|
|
|
|
int i, len;
|
|
|
|
clb_net = (struct s_net *) my_malloc(num_nets * sizeof(struct s_net));
|
|
for (i = 0; i < NET_COUNT; i++) {
|
|
/* FIXME: We *really* shouldn't be allocating write-once copies */
|
|
len = strlen("TEMP_NET");
|
|
clb_net[i].name = (char *) my_malloc((len + 1) * sizeof(char));
|
|
clb_net[i].is_global = FALSE;
|
|
strcpy(clb_net[NET_USED].name, "TEMP_NET");
|
|
|
|
clb_net[i].num_sinks = (BLOCK_COUNT - 1);
|
|
clb_net[i].node_block = (int *) my_malloc(BLOCK_COUNT * sizeof(int));
|
|
clb_net[i].node_block[NET_USED_SOURCE_BLOCK] = NET_USED_SOURCE_BLOCK; /*driving block */
|
|
clb_net[i].node_block[NET_USED_SINK_BLOCK] = NET_USED_SINK_BLOCK; /*target block */
|
|
|
|
clb_net[i].node_block_pin = (int *) my_malloc(
|
|
BLOCK_COUNT * sizeof(int));
|
|
/*the values for this are allocated in assign_blocks_and_route_net */
|
|
|
|
}
|
|
}
|
|
|
|
/**************************************/
|
|
static void alloc_block(void) {
|
|
|
|
/*allocates block structure, and assigns values to known parameters */
|
|
/*type and x,y fields are left undefined at this stage since they */
|
|
/*are not known until we start moving blocks through the clb array */
|
|
|
|
int ix_b, ix_p, len, i;
|
|
int max_pins;
|
|
|
|
max_pins = 0;
|
|
for (i = 0; i < NUM_TYPES_USED; i++) {
|
|
max_pins = std::max(max_pins, type_descriptors[i].num_pins);
|
|
}
|
|
|
|
block = (struct s_block *) my_malloc(num_blocks * sizeof(struct s_block));
|
|
|
|
for (ix_b = 0; ix_b < BLOCK_COUNT; ix_b++) {
|
|
len = strlen("TEMP_BLOCK");
|
|
block[ix_b].name = (char *) my_malloc((len + 1) * sizeof(char));
|
|
strcpy(block[ix_b].name, "TEMP_BLOCK");
|
|
|
|
block[ix_b].nets = (int *) my_malloc(max_pins * sizeof(int));
|
|
block[ix_b].nets[0] = 0;
|
|
for (ix_p = 1; ix_p < max_pins; ix_p++)
|
|
block[ix_b].nets[ix_p] = OPEN;
|
|
}
|
|
}
|
|
|
|
/**************************************/
|
|
static void load_simplified_device(void) {
|
|
int i, j;
|
|
|
|
/* Backup original globals */
|
|
EMPTY_TYPE_BACKUP = EMPTY_TYPE;
|
|
IO_TYPE_BACKUP = IO_TYPE;
|
|
FILL_TYPE_BACKUP = FILL_TYPE;
|
|
type_descriptors_backup = type_descriptors;
|
|
num_types_backup = num_types;
|
|
num_types = NUM_TYPES_USED;
|
|
|
|
/* Fill in homogeneous core type info */
|
|
dummy_type_descriptors[0] = *EMPTY_TYPE;
|
|
dummy_type_descriptors[0].index = 0;
|
|
dummy_type_descriptors[1] = *IO_TYPE;
|
|
dummy_type_descriptors[1].index = 1;
|
|
dummy_type_descriptors[2] = *FILL_TYPE;
|
|
dummy_type_descriptors[2].index = 2;
|
|
type_descriptors = dummy_type_descriptors;
|
|
EMPTY_TYPE = &dummy_type_descriptors[0];
|
|
IO_TYPE = &dummy_type_descriptors[1];
|
|
FILL_TYPE = &dummy_type_descriptors[2];
|
|
|
|
/* Fill in homogeneous core grid info */
|
|
grid_backup = grid;
|
|
grid = (struct s_grid_tile **) alloc_matrix(0, nx + 1, 0, ny + 1,
|
|
sizeof(struct s_grid_tile));
|
|
for (i = 0; i < nx + 2; i++) {
|
|
for (j = 0; j < ny + 2; j++) {
|
|
if ((i == 0 && j == 0) || (i == nx + 1 && j == 0)
|
|
|| (i == 0 && j == ny + 1)
|
|
|| (i == nx + 1 && j == ny + 1)) {
|
|
grid[i][j].type = EMPTY_TYPE;
|
|
} else if (i == 0 || i == nx + 1 || j == 0 || j == ny + 1) {
|
|
grid[i][j].type = IO_TYPE;
|
|
} else {
|
|
grid[i][j].type = FILL_TYPE;
|
|
}
|
|
grid[i][j].blocks = (int*)my_malloc(
|
|
grid[i][j].type->capacity * sizeof(int));
|
|
grid[i][j].offset = 0;
|
|
}
|
|
}
|
|
}
|
|
static void restore_original_device(void) {
|
|
int i, j;
|
|
|
|
/* restore previous globals */
|
|
IO_TYPE = IO_TYPE_BACKUP;
|
|
EMPTY_TYPE = EMPTY_TYPE_BACKUP;
|
|
FILL_TYPE = FILL_TYPE_BACKUP;
|
|
type_descriptors = type_descriptors_backup;
|
|
num_types = num_types_backup;
|
|
|
|
/* free allocatd data */
|
|
for (i = 0; i < nx + 2; i++) {
|
|
for (j = 0; j < ny + 2; j++) {
|
|
free(grid[i][j].blocks);
|
|
}
|
|
}
|
|
free_matrix(grid, 0, nx + 1, 0, sizeof(struct s_grid_tile));
|
|
grid = grid_backup;
|
|
}
|
|
|
|
/**************************************/
|
|
static void reset_placement(void) {
|
|
int i, j, k;
|
|
|
|
for (i = 0; i <= nx + 1; i++) {
|
|
for (j = 0; j <= ny + 1; j++) {
|
|
grid[i][j].usage = 0;
|
|
for (k = 0; k < grid[i][j].type->capacity; k++) {
|
|
grid[i][j].blocks[k] = EMPTY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************/
|
|
static void alloc_and_assign_internal_structures(struct s_net **original_net,
|
|
struct s_block **original_block, int *original_num_nets,
|
|
int *original_num_blocks) {
|
|
/*allocate new data structures to hold net, and block info */
|
|
|
|
*original_net = clb_net;
|
|
*original_num_nets = num_nets;
|
|
num_nets = NET_COUNT;
|
|
alloc_net();
|
|
|
|
*original_block = block;
|
|
*original_num_blocks = num_blocks;
|
|
num_blocks = BLOCK_COUNT;
|
|
alloc_block();
|
|
|
|
/* [0..num_nets-1][1..num_pins-1] */
|
|
net_delay = (float **) alloc_matrix(0, NET_COUNT - 1, 1, BLOCK_COUNT - 1,
|
|
sizeof(float));
|
|
|
|
reset_placement();
|
|
}
|
|
|
|
/**************************************/
|
|
static void free_and_reset_internal_structures(struct s_net *original_net,
|
|
struct s_block *original_block, int original_num_nets,
|
|
int original_num_blocks) {
|
|
/*reset gloabal data structures to the state that they were in before these */
|
|
/*lookup computation routines were called */
|
|
|
|
int i;
|
|
|
|
/*there should be only one net to free, but this is safer */
|
|
for (i = 0; i < NET_COUNT; i++) {
|
|
free(clb_net[i].name);
|
|
free(clb_net[i].node_block);
|
|
free(clb_net[i].node_block_pin);
|
|
}
|
|
free(clb_net);
|
|
clb_net = original_net;
|
|
|
|
for (i = 0; i < BLOCK_COUNT; i++) {
|
|
free(block[i].name);
|
|
free(block[i].nets);
|
|
}
|
|
free(block);
|
|
block = original_block;
|
|
|
|
num_nets = original_num_nets;
|
|
num_blocks = original_num_blocks;
|
|
|
|
free_matrix(net_delay, 0, NET_COUNT - 1, 1, sizeof(float));
|
|
|
|
}
|
|
|
|
/**************************************/
|
|
static void setup_chan_width(struct s_router_opts router_opts,
|
|
t_chan_width_dist chan_width_dist) {
|
|
/*we give plenty of tracks, this increases routability for the */
|
|
/*lookup table generation */
|
|
|
|
int width_fac, i, max_pins_per_clb;
|
|
|
|
max_pins_per_clb = 0;
|
|
for (i = 0; i < num_types; i++) {
|
|
max_pins_per_clb = std::max(max_pins_per_clb, type_descriptors[i].num_pins);
|
|
}
|
|
|
|
if (router_opts.fixed_channel_width == NO_FIXED_CHANNEL_WIDTH)
|
|
width_fac = 4 * max_pins_per_clb; /*this is 2x the value that binary search starts */
|
|
/*this should be enough to allow most pins to */
|
|
/*connect to tracks in the architecture */
|
|
else
|
|
width_fac = router_opts.fixed_channel_width;
|
|
|
|
init_chan(width_fac, chan_width_dist);
|
|
}
|
|
|
|
/**************************************/
|
|
static void alloc_routing_structs(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf, INP t_direct_inf *directs,
|
|
INP int num_directs) {
|
|
|
|
int bb_factor;
|
|
int warnings;
|
|
t_graph_type graph_type;
|
|
|
|
/*calls routines that set up routing resource graph and associated structures */
|
|
|
|
/*must set up dummy blocks for the first pass through to setup locally used opins */
|
|
/* Only one block per tile */
|
|
assign_locations(FILL_TYPE, 1, 1, 0, FILL_TYPE, nx, ny, 0);
|
|
|
|
clb_opins_used_locally = alloc_route_structs();
|
|
|
|
free_rr_graph();
|
|
|
|
if (router_opts.route_type == GLOBAL) {
|
|
graph_type = GRAPH_GLOBAL;
|
|
} else {
|
|
graph_type = (
|
|
det_routing_arch.directionality == BI_DIRECTIONAL ?
|
|
GRAPH_BIDIR : GRAPH_UNIDIR);
|
|
}
|
|
|
|
build_rr_graph(graph_type, num_types, dummy_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,
|
|
NULL, 0, TRUE, /* do not send in direct connections because we care about general placement timing instead of special pin placement timing */
|
|
&warnings, 0, NULL, FALSE, FALSE);
|
|
|
|
alloc_and_load_rr_node_route_structs();
|
|
|
|
alloc_timing_driven_route_structs(&pin_criticality, &sink_order,
|
|
&rt_node_of_sink);
|
|
|
|
bb_factor = nx + ny; /*set it to a huge value */
|
|
init_route_structs(bb_factor);
|
|
}
|
|
|
|
/**************************************/
|
|
static void free_routing_structs(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf) {
|
|
int i;
|
|
free_rr_graph();
|
|
|
|
free_rr_node_route_structs();
|
|
free_route_structs();
|
|
free_trace_structs();
|
|
|
|
free_timing_driven_route_structs(pin_criticality, sink_order,
|
|
rt_node_of_sink);
|
|
|
|
if (clb_opins_used_locally != NULL) {
|
|
for (i = 0; i < num_blocks; i++) {
|
|
free_ivec_vector(clb_opins_used_locally[i], 0,
|
|
block[i].type->num_class - 1);
|
|
}
|
|
free(clb_opins_used_locally);
|
|
clb_opins_used_locally = NULL;
|
|
}
|
|
}
|
|
|
|
/**************************************/
|
|
static void assign_locations(t_type_ptr source_type, int source_x_loc,
|
|
int source_y_loc, int source_z_loc, t_type_ptr sink_type,
|
|
int sink_x_loc, int sink_y_loc, int sink_z_loc) {
|
|
/*all routing occurs between block 0 (source) and block 1 (sink) */
|
|
block[SOURCE_BLOCK].type = source_type;
|
|
block[SOURCE_BLOCK].x = source_x_loc;
|
|
block[SOURCE_BLOCK].y = source_y_loc;
|
|
block[SOURCE_BLOCK].z = source_z_loc;
|
|
|
|
block[SINK_BLOCK].type = sink_type;
|
|
block[SINK_BLOCK].x = sink_x_loc;
|
|
block[SINK_BLOCK].y = sink_y_loc;
|
|
block[SINK_BLOCK].z = sink_z_loc;
|
|
|
|
grid[source_x_loc][source_y_loc].blocks[source_z_loc] = SOURCE_BLOCK;
|
|
grid[sink_x_loc][sink_y_loc].blocks[sink_z_loc] = SINK_BLOCK;
|
|
|
|
clb_net[NET_USED].node_block_pin[NET_USED_SOURCE_BLOCK] = get_first_pin(
|
|
DRIVER, block[SOURCE_BLOCK].type);
|
|
clb_net[NET_USED].node_block_pin[NET_USED_SINK_BLOCK] = get_first_pin(
|
|
RECEIVER, block[SINK_BLOCK].type);
|
|
|
|
grid[source_x_loc][source_y_loc].usage += 1;
|
|
grid[sink_x_loc][sink_y_loc].usage += 1;
|
|
|
|
}
|
|
|
|
/**************************************/
|
|
static float assign_blocks_and_route_net(t_type_ptr source_type,
|
|
int source_x_loc, int source_y_loc, t_type_ptr sink_type,
|
|
int sink_x_loc, int sink_y_loc, struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf) {
|
|
/*places blocks at the specified locations, and routes a net between them */
|
|
/*returns the delay of this net */
|
|
|
|
float pres_fac, net_delay_value;
|
|
|
|
int source_z_loc, sink_z_loc;
|
|
|
|
/* Only one block per tile */
|
|
source_z_loc = 0;
|
|
sink_z_loc = 0;
|
|
|
|
net_delay_value = IMPOSSIBLE; /*set to known value for debug purposes */
|
|
|
|
assign_locations(source_type, source_x_loc, source_y_loc, source_z_loc,
|
|
sink_type, sink_x_loc, sink_y_loc, sink_z_loc);
|
|
|
|
load_net_rr_terminals(rr_node_indices);
|
|
|
|
pres_fac = 0; /* ignore congestion */
|
|
|
|
/* Route this net with a dummy criticality of 0 by calling
|
|
timing_driven_route_net with slacks set to NULL. */
|
|
timing_driven_route_net(NET_USED, pres_fac,
|
|
router_opts.max_criticality, router_opts.criticality_exp,
|
|
router_opts.astar_fac, router_opts.bend_cost,
|
|
pin_criticality, sink_order, rt_node_of_sink,
|
|
net_delay[NET_USED], NULL);
|
|
|
|
/* mrFPGA */
|
|
if (is_mrFPGA && is_wire_buffer) {
|
|
buffer_net(net_delay[NET_USED]);
|
|
}
|
|
/* end */
|
|
|
|
net_delay_value = net_delay[NET_USED][NET_USED_SINK_BLOCK];
|
|
|
|
grid[source_x_loc][source_y_loc].usage = 0;
|
|
grid[source_x_loc][source_y_loc].blocks[source_z_loc] = EMPTY;
|
|
grid[sink_x_loc][sink_y_loc].usage = 0;
|
|
grid[sink_x_loc][sink_y_loc].blocks[sink_z_loc] = EMPTY;
|
|
|
|
return (net_delay_value);
|
|
}
|
|
|
|
/**************************************/
|
|
static void alloc_delta_arrays(void) {
|
|
int id_x, id_y;
|
|
|
|
delta_clb_to_clb = (float **) alloc_matrix(0, nx - 1, 0, ny - 1,
|
|
sizeof(float));
|
|
delta_io_to_clb = (float **) alloc_matrix(0, nx, 0, ny, sizeof(float));
|
|
delta_clb_to_io = (float **) alloc_matrix(0, nx, 0, ny, sizeof(float));
|
|
delta_io_to_io = (float **) alloc_matrix(0, nx + 1, 0, ny + 1,
|
|
sizeof(float));
|
|
|
|
/*initialize all of the array locations to -1 */
|
|
|
|
for (id_x = 0; id_x <= nx; id_x++) {
|
|
for (id_y = 0; id_y <= ny; id_y++) {
|
|
delta_io_to_clb[id_x][id_y] = IMPOSSIBLE;
|
|
}
|
|
}
|
|
for (id_x = 0; id_x <= nx - 1; id_x++) {
|
|
for (id_y = 0; id_y <= ny - 1; id_y++) {
|
|
delta_clb_to_clb[id_x][id_y] = IMPOSSIBLE;
|
|
}
|
|
}
|
|
for (id_x = 0; id_x <= nx; id_x++) {
|
|
for (id_y = 0; id_y <= ny; id_y++) {
|
|
delta_clb_to_io[id_x][id_y] = IMPOSSIBLE;
|
|
}
|
|
}
|
|
for (id_x = 0; id_x <= nx + 1; id_x++) {
|
|
for (id_y = 0; id_y <= ny + 1; id_y++) {
|
|
delta_io_to_io[id_x][id_y] = IMPOSSIBLE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************/
|
|
static void free_delta_arrays(void) {
|
|
|
|
free_matrix(delta_io_to_clb, 0, nx, 0, sizeof(float));
|
|
free_matrix(delta_clb_to_clb, 0, nx - 1, 0, sizeof(float));
|
|
free_matrix(delta_clb_to_io, 0, nx, 0, sizeof(float));
|
|
free_matrix(delta_io_to_io, 0, nx + 1, 0, sizeof(float));
|
|
|
|
}
|
|
|
|
/**************************************/
|
|
static void generic_compute_matrix(float ***matrix_ptr, t_type_ptr source_type,
|
|
t_type_ptr sink_type, int source_x, int source_y, int start_x,
|
|
int end_x, int start_y, int end_y, struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf) {
|
|
|
|
int delta_x, delta_y;
|
|
int sink_x, sink_y;
|
|
|
|
for (sink_x = start_x; sink_x <= end_x; sink_x++) {
|
|
for (sink_y = start_y; sink_y <= end_y; sink_y++) {
|
|
delta_x = abs(sink_x - source_x);
|
|
delta_y = abs(sink_y - source_y);
|
|
|
|
if (delta_x == 0 && delta_y == 0)
|
|
continue; /*do not compute distance from a block to itself */
|
|
/*if a value is desired, pre-assign it somewhere else */
|
|
|
|
(*matrix_ptr)[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************/
|
|
static void compute_delta_clb_to_clb(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf, int longest_length) {
|
|
|
|
/*this routine must compute delay values in a slightly different way than the */
|
|
/*other compute routines. We cannot use a location close to the edge as the */
|
|
/*source location for the majority of the delay computations because this */
|
|
/*would give gradually increasing delay values. To avoid this from happening */
|
|
/*a clb that is at least longest_length away from an edge should be chosen */
|
|
/*as a source , if longest_length is more than 0.5 of the total size then */
|
|
/*choose a CLB at the center as the source CLB */
|
|
|
|
int source_x, source_y, sink_x, sink_y;
|
|
int start_x, start_y, end_x, end_y;
|
|
int delta_x, delta_y;
|
|
t_type_ptr source_type, sink_type;
|
|
|
|
source_type = FILL_TYPE;
|
|
sink_type = FILL_TYPE;
|
|
|
|
if (longest_length < 0.5 * (nx)) {
|
|
start_x = longest_length;
|
|
} else {
|
|
start_x = (int) (0.5 * nx);
|
|
}
|
|
end_x = nx;
|
|
source_x = start_x;
|
|
|
|
if (longest_length < 0.5 * (ny)) {
|
|
start_y = longest_length;
|
|
} else {
|
|
start_y = (int) (0.5 * ny);
|
|
}
|
|
end_y = ny;
|
|
source_y = start_y;
|
|
|
|
/*don't put the sink all the way to the corner, until it is necessary */
|
|
for (sink_x = start_x; sink_x <= end_x - 1; sink_x++) {
|
|
for (sink_y = start_y; sink_y <= end_y - 1; sink_y++) {
|
|
delta_x = abs(sink_x - source_x);
|
|
delta_y = abs(sink_y - source_y);
|
|
|
|
if (delta_x == 0 && delta_y == 0) {
|
|
delta_clb_to_clb[delta_x][delta_y] = 0.0;
|
|
continue;
|
|
}
|
|
delta_clb_to_clb[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
}
|
|
|
|
}
|
|
|
|
sink_x = end_x - 1;
|
|
sink_y = end_y - 1;
|
|
|
|
for (source_x = start_x - 1; source_x >= 1; source_x--) {
|
|
for (source_y = start_y; source_y <= end_y - 1; source_y++) {
|
|
delta_x = abs(sink_x - source_x);
|
|
delta_y = abs(sink_y - source_y);
|
|
|
|
delta_clb_to_clb[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
}
|
|
}
|
|
|
|
for (source_x = 1; source_x <= end_x - 1; source_x++) {
|
|
for (source_y = 1; source_y < start_y; source_y++) {
|
|
delta_x = abs(sink_x - source_x);
|
|
delta_y = abs(sink_y - source_y);
|
|
|
|
delta_clb_to_clb[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
}
|
|
}
|
|
|
|
/*now move sink into the top right corner */
|
|
sink_x = end_x;
|
|
sink_y = end_y;
|
|
source_x = 1;
|
|
for (source_y = 1; source_y <= end_y; source_y++) {
|
|
delta_x = abs(sink_x - source_x);
|
|
delta_y = abs(sink_y - source_y);
|
|
|
|
delta_clb_to_clb[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
|
|
}
|
|
|
|
sink_x = end_x;
|
|
sink_y = end_y;
|
|
source_y = 1;
|
|
for (source_x = 1; source_x <= end_x; source_x++) {
|
|
delta_x = abs(sink_x - source_x);
|
|
delta_y = abs(sink_y - source_y);
|
|
|
|
delta_clb_to_clb[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
}
|
|
}
|
|
|
|
/**************************************/
|
|
static void compute_delta_io_to_clb(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf) {
|
|
int source_x, source_y;
|
|
int start_x, start_y, end_x, end_y;
|
|
t_type_ptr source_type, sink_type;
|
|
|
|
source_type = IO_TYPE;
|
|
sink_type = FILL_TYPE;
|
|
|
|
delta_io_to_clb[0][0] = IMPOSSIBLE;
|
|
delta_io_to_clb[nx][ny] = IMPOSSIBLE;
|
|
|
|
source_x = 0;
|
|
source_y = 1;
|
|
|
|
start_x = 1;
|
|
end_x = nx;
|
|
start_y = 1;
|
|
end_y = ny;
|
|
generic_compute_matrix(&delta_io_to_clb, source_type, sink_type, source_x,
|
|
source_y, start_x, end_x, start_y, end_y, router_opts,
|
|
det_routing_arch, segment_inf, timing_inf);
|
|
|
|
source_x = 1;
|
|
source_y = 0;
|
|
|
|
start_x = 1;
|
|
end_x = 1;
|
|
start_y = 1;
|
|
end_y = ny;
|
|
generic_compute_matrix(&delta_io_to_clb, source_type, sink_type, source_x,
|
|
source_y, start_x, end_x, start_y, end_y, router_opts,
|
|
det_routing_arch, segment_inf, timing_inf);
|
|
|
|
start_x = 1;
|
|
end_x = nx;
|
|
start_y = ny;
|
|
end_y = ny;
|
|
generic_compute_matrix(&delta_io_to_clb, source_type, sink_type, source_x,
|
|
source_y, start_x, end_x, start_y, end_y, router_opts,
|
|
det_routing_arch, segment_inf, timing_inf);
|
|
}
|
|
|
|
/**************************************/
|
|
static void compute_delta_clb_to_io(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf) {
|
|
int source_x, source_y, sink_x, sink_y;
|
|
int delta_x, delta_y;
|
|
t_type_ptr source_type, sink_type;
|
|
|
|
source_type = FILL_TYPE;
|
|
sink_type = IO_TYPE;
|
|
|
|
delta_clb_to_io[0][0] = IMPOSSIBLE;
|
|
delta_clb_to_io[nx][ny] = IMPOSSIBLE;
|
|
|
|
sink_x = 0;
|
|
sink_y = 1;
|
|
for (source_x = 1; source_x <= nx; source_x++) {
|
|
for (source_y = 1; source_y <= ny; source_y++) {
|
|
delta_x = abs(source_x - sink_x);
|
|
delta_y = abs(source_y - sink_y);
|
|
|
|
delta_clb_to_io[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
}
|
|
}
|
|
|
|
sink_x = 1;
|
|
sink_y = 0;
|
|
source_x = 1;
|
|
delta_x = abs(source_x - sink_x);
|
|
for (source_y = 1; source_y <= ny; source_y++) {
|
|
delta_y = abs(source_y - sink_y);
|
|
delta_clb_to_io[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
}
|
|
|
|
sink_x = 1;
|
|
sink_y = 0;
|
|
source_y = ny;
|
|
delta_y = abs(source_y - sink_y);
|
|
for (source_x = 2; source_x <= nx; source_x++) {
|
|
delta_x = abs(source_x - sink_x);
|
|
delta_clb_to_io[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
}
|
|
}
|
|
|
|
/**************************************/
|
|
static void compute_delta_io_to_io(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf) {
|
|
int source_x, source_y, sink_x, sink_y;
|
|
int delta_x, delta_y;
|
|
t_type_ptr source_type, sink_type;
|
|
|
|
source_type = IO_TYPE;
|
|
sink_type = IO_TYPE;
|
|
|
|
delta_io_to_io[0][0] = 0; /*delay to itself is 0 (this can happen) */
|
|
delta_io_to_io[nx + 1][ny + 1] = IMPOSSIBLE;
|
|
delta_io_to_io[0][ny] = IMPOSSIBLE;
|
|
delta_io_to_io[nx][0] = IMPOSSIBLE;
|
|
delta_io_to_io[nx][ny + 1] = IMPOSSIBLE;
|
|
delta_io_to_io[nx + 1][ny] = IMPOSSIBLE;
|
|
|
|
source_x = 0;
|
|
source_y = 1;
|
|
sink_x = 0;
|
|
delta_x = abs(sink_x - source_x);
|
|
|
|
for (sink_y = 2; sink_y <= ny; sink_y++) {
|
|
delta_y = abs(sink_y - source_y);
|
|
delta_io_to_io[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
|
|
}
|
|
|
|
source_x = 0;
|
|
source_y = 1;
|
|
sink_x = nx + 1;
|
|
delta_x = abs(sink_x - source_x);
|
|
|
|
for (sink_y = 1; sink_y <= ny; sink_y++) {
|
|
delta_y = abs(sink_y - source_y);
|
|
delta_io_to_io[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
|
|
}
|
|
|
|
source_x = 1;
|
|
source_y = 0;
|
|
sink_y = 0;
|
|
delta_y = abs(sink_y - source_y);
|
|
|
|
for (sink_x = 2; sink_x <= nx; sink_x++) {
|
|
delta_x = abs(sink_x - source_x);
|
|
delta_io_to_io[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
|
|
}
|
|
|
|
source_x = 1;
|
|
source_y = 0;
|
|
sink_y = ny + 1;
|
|
delta_y = abs(sink_y - source_y);
|
|
|
|
for (sink_x = 1; sink_x <= nx; sink_x++) {
|
|
delta_x = abs(sink_x - source_x);
|
|
delta_io_to_io[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
|
|
}
|
|
|
|
source_x = 0;
|
|
sink_y = ny + 1;
|
|
for (source_y = 1; source_y <= ny; source_y++) {
|
|
for (sink_x = 1; sink_x <= nx; sink_x++) {
|
|
delta_y = abs(source_y - sink_y);
|
|
delta_x = abs(source_x - sink_x);
|
|
delta_io_to_io[delta_x][delta_y] = assign_blocks_and_route_net(
|
|
source_type, source_x, source_y, sink_type, sink_x, sink_y,
|
|
router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************/
|
|
#ifdef PRINT_ARRAYS
|
|
static void
|
|
print_array(float **array_to_print,
|
|
int x1,
|
|
int x2,
|
|
int y1,
|
|
int y2)
|
|
{
|
|
|
|
int idx_x, idx_y;
|
|
|
|
fprintf(lookup_dump, "\nPrinting Array \n\n");
|
|
|
|
for (idx_y = y2; idx_y >= y1; idx_y--)
|
|
{
|
|
for (idx_x = x1; idx_x <= x2; idx_x++)
|
|
{
|
|
fprintf(lookup_dump, " %9.2e",
|
|
array_to_print[idx_x][idx_y]);
|
|
}
|
|
fprintf(lookup_dump, "\n");
|
|
}
|
|
fprintf(lookup_dump, "\n\n");
|
|
}
|
|
#endif
|
|
/**************************************/
|
|
static void compute_delta_arrays(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf, int longest_length) {
|
|
|
|
vpr_printf(TIO_MESSAGE_INFO, "Computing delta_io_to_io lookup matrix, may take a few seconds, please wait...\n");
|
|
compute_delta_io_to_io(router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
vpr_printf(TIO_MESSAGE_INFO, "Computing delta_io_to_clb lookup matrix, may take a few seconds, please wait...\n");
|
|
compute_delta_io_to_clb(router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
vpr_printf(TIO_MESSAGE_INFO, "Computing delta_clb_to_io lookup matrix, may take a few seconds, please wait...\n");
|
|
compute_delta_clb_to_io(router_opts, det_routing_arch, segment_inf, timing_inf);
|
|
vpr_printf(TIO_MESSAGE_INFO, "Computing delta_clb_to_clb lookup matrix, may take a few seconds, please wait...\n");
|
|
compute_delta_clb_to_clb(router_opts, det_routing_arch, segment_inf, timing_inf, longest_length);
|
|
|
|
#ifdef PRINT_ARRAYS
|
|
lookup_dump = my_fopen(DUMPFILE, "w", 0);
|
|
fprintf(lookup_dump, "\n\nprinting delta_clb_to_clb\n");
|
|
print_array(delta_clb_to_clb, 0, nx - 1, 0, ny - 1);
|
|
fprintf(lookup_dump, "\n\nprinting delta_io_to_clb\n");
|
|
print_array(delta_io_to_clb, 0, nx, 0, ny);
|
|
fprintf(lookup_dump, "\n\nprinting delta_clb_to_io\n");
|
|
print_array(delta_clb_to_io, 0, nx, 0, ny);
|
|
fprintf(lookup_dump, "\n\nprinting delta_io_to_io\n");
|
|
print_array(delta_io_to_io, 0, nx + 1, 0, ny + 1);
|
|
fclose(lookup_dump);
|
|
#endif
|
|
|
|
}
|
|
|
|
/******* Globally Accessable Functions **********/
|
|
|
|
/**************************************/
|
|
void compute_delay_lookup_tables(struct s_router_opts router_opts,
|
|
struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf,
|
|
t_timing_inf timing_inf, t_chan_width_dist chan_width_dist, INP t_direct_inf *directs,
|
|
INP int num_directs) {
|
|
|
|
static struct s_net *original_net; /*this will be used as a pointer to remember what */
|
|
|
|
/*the "real" nets in the circuit are. This is */
|
|
/*required because we are using the net structure */
|
|
/*in these routines to find delays between blocks */
|
|
static struct s_block *original_block; /*same def as original_nets, but for block */
|
|
|
|
static int original_num_nets;
|
|
static int original_num_blocks;
|
|
static int longest_length;
|
|
|
|
load_simplified_device();
|
|
|
|
alloc_and_assign_internal_structures(&original_net, &original_block,
|
|
&original_num_nets, &original_num_blocks);
|
|
setup_chan_width(router_opts, chan_width_dist);
|
|
|
|
alloc_routing_structs(router_opts, det_routing_arch, segment_inf,
|
|
timing_inf, directs, num_directs);
|
|
|
|
longest_length = get_longest_segment_length(det_routing_arch, segment_inf);
|
|
|
|
/*now setup and compute the actual arrays */
|
|
alloc_delta_arrays();
|
|
compute_delta_arrays(router_opts, det_routing_arch, segment_inf, timing_inf,
|
|
longest_length);
|
|
|
|
/*free all data structures that are no longer needed */
|
|
free_routing_structs(router_opts, det_routing_arch, segment_inf,
|
|
timing_inf);
|
|
|
|
restore_original_device();
|
|
|
|
free_and_reset_internal_structures(original_net, original_block,
|
|
original_num_nets, original_num_blocks);
|
|
}
|
|
|
|
/**************************************/
|
|
void free_place_lookup_structs(void) {
|
|
|
|
free_delta_arrays();
|
|
|
|
}
|
|
|
|
/* mrFPGA */
|
|
static void buffer_net( float* cur_net_delay )
|
|
{
|
|
t_rc_node *rc_node_free_list;
|
|
t_linked_rc_edge *rc_edge_free_list;
|
|
//int inet;
|
|
t_linked_rc_ptr *rr_node_to_rc_node; /* [0..num_rr_nodes-1] */
|
|
|
|
vpr_printf(TIO_MESSAGE_INFO, "mrFPGA: net delay before buffer: %g\n", cur_net_delay[NET_USED_SINK_BLOCK] );
|
|
rr_node_to_rc_node = (t_linked_rc_ptr *) my_calloc (num_rr_nodes,
|
|
sizeof (t_linked_rc_ptr));
|
|
|
|
rc_node_free_list = NULL;
|
|
rc_edge_free_list = NULL;
|
|
try_buffer_for_net( NET_USED, &rc_node_free_list, &rc_edge_free_list, rr_node_to_rc_node, cur_net_delay );
|
|
free_rc_node_free_list (rc_node_free_list);
|
|
free_rc_edge_free_list (rc_edge_free_list);
|
|
free (rr_node_to_rc_node);
|
|
vpr_printf(TIO_MESSAGE_INFO, "mrFPGA: net delay after buffer: %g\n", cur_net_delay[NET_USED_SINK_BLOCK] );
|
|
}
|
|
/* end */
|