OpenFPGA/vpr7_x2p/vpr/SRC/base/draw.c

2107 lines
61 KiB
C
Raw Normal View History

2018-07-26 12:28:21 -05:00
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include "vpr_types.h"
#include "vpr_utils.h"
#include "globals.h"
#include "graphics.h"
#include "path_delay.h"
#include "draw.h"
#include <assert.h>
#include "read_xml_arch_file.h"
#include "util.h"
#ifdef DEBUG
#include "rr_graph.h"
#endif
/*************** Types local to this module *********************************/
#define MAX_BLOCK_COLOURS 5
enum e_draw_rr_toggle {
DRAW_NO_RR = 0,
DRAW_ALL_RR,
DRAW_ALL_BUT_BUFFERS_RR,
DRAW_NODES_AND_SBOX_RR,
DRAW_NODES_RR,
DRAW_RR_TOGGLE_MAX
};
enum e_draw_net_type {
ALL_NETS, HIGHLIGHTED
};
enum e_edge_dir {
FROM_X_TO_Y, FROM_Y_TO_X
};
/* Chanx to chany or vice versa? */
/****************** Variables local to this module. *************************/
static boolean show_nets = FALSE; /* Show nets of placement or routing? */
/* Controls drawing of routing resources on screen, if pic_on_screen is *
* ROUTING. */
/* Can toggle to DRAW_NO_RR;*/
static enum e_draw_rr_toggle draw_rr_toggle = DRAW_NO_RR; /* UDSD by AY */
static enum e_route_type draw_route_type;
/* Controls if congestion is shown, when ROUTING is on screen. */
static boolean show_congestion = FALSE;
static boolean show_defects = FALSE; /* Show defective stuff */
static boolean show_graphics; /* Graphics enabled or not? */
static char default_message[BUFSIZE]; /* Default screen message on screen */
static int gr_automode; /* Need user input after: 0: each t, *
* 1: each place, 2: never */
static enum pic_type pic_on_screen = NO_PICTURE; /* What do I draw? */
static float *tile_x, *tile_y;
/* The left and bottom coordinates of each grid_tile in the FPGA. *
* tile_x[0..nx+1] and tile_y[0..ny+1]. *
* COORDINATE SYSTEM goes from (0,0) at the lower left corner to *
* (tile_x[nx+1]+tile_width, tile_y[ny+1]+tile_width) in the *
* upper right corner. */
static float tile_width, pin_size;
/* Drawn width (and height) of a grid_tile, and the half-width or half-height of *
* a pin, respectiviely. Set when init_draw_coords is called. */
static enum color_types *net_color, *block_color;
/* Color in which each block and net should be drawn. *
* [0..num_nets-1] and [0..num_blocks-1], respectively. */
static float line_fuz = 0.3;
static const char *name_type[] = { "SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY",
"INTRA_CLUSTER_EDGE" };
static float *x_rr_node_left = NULL;
static float *x_rr_node_right = NULL;
static float *y_rr_node_top = NULL;
static float *y_rr_node_bottom = NULL;
static enum color_types *rr_node_color = NULL;
static int old_num_rr_nodes = 0;
/********************** Subroutines local to this module ********************/
static void toggle_nets(void (*drawscreen)(void));
static void toggle_rr(void (*drawscreen)(void));
static void toggle_defects(void (*drawscreen)(void));
static void toggle_congestion(void (*drawscreen)(void));
static void highlight_crit_path(void (*drawscreen_ptr)(void));
static void drawscreen(void);
static void redraw_screen(void);
static void drawplace(void);
static void drawnets(void);
static void drawroute(enum e_draw_net_type draw_net_type);
static void draw_congestion(void);
static void highlight_blocks(float x, float y);
static void get_block_center(int bnum, float *x, float *y);
static void deselect_all(void);
static void draw_rr(void);
static void draw_rr_edges(int from_node);
static void draw_rr_pin(int inode, enum color_types color);
static void draw_rr_chanx(int inode, int itrack);
static void draw_rr_chany(int inode, int itrack);
static void get_rr_pin_draw_coords(int inode, int iside, int ioff, float *xcen,
float *ycen);
static void draw_pin_to_chan_edge(int pin_node, int chan_node);
static void draw_pin_to_pin(int opin, int ipin);
static void draw_x(float x, float y, float size);
static void draw_chany_to_chany_edge(int from_node, int from_track, int to_node,
int to_track, short switch_type);
static void draw_chanx_to_chanx_edge(int from_node, int from_track, int to_node,
int to_track, short switch_type);
static void draw_chanx_to_chany_edge(int chanx_node, int chanx_track,
int chany_node, int chany_track, enum e_edge_dir edge_dir,
short switch_type);
static int get_track_num(int inode, int **chanx_track, int **chany_track);
static void draw_rr_switch(float from_x, float from_y, float to_x, float to_y,
boolean buffered);
static void draw_triangle_along_line(float xend, float yend, /* UDSD by AY */
float x1, float x2, /* UDSD by AY */
float y1, float y2); /* UDSD by AY */
/********************** Subroutine definitions ******************************/
void set_graphics_state(boolean show_graphics_val, int gr_automode_val,
enum e_route_type route_type) {
/* Sets the static show_graphics and gr_automode variables to the *
* desired values. They control if graphics are enabled and, if so, *
* how often the user is prompted for input. */
show_graphics = show_graphics_val;
gr_automode = gr_automode_val;
draw_route_type = route_type;
}
void update_screen(int priority, char *msg, enum pic_type pic_on_screen_val,
boolean crit_path_button_enabled) {
/* Updates the screen if the user has requested graphics. The priority *
* value controls whether or not the Proceed button must be clicked to *
* continue. Saves the pic_on_screen_val to allow pan and zoom redraws. */
if (!show_graphics) /* Graphics turned off */
return;
/* If it's the type of picture displayed has changed, set up the proper *
* buttons. */
if (pic_on_screen != pic_on_screen_val) {
if (pic_on_screen_val == PLACEMENT && pic_on_screen == NO_PICTURE) {
create_button("Window", "Toggle Nets", toggle_nets);
} else if (pic_on_screen_val == ROUTING && pic_on_screen == PLACEMENT) {
create_button("Toggle Nets", "Toggle RR", toggle_rr);
create_button("Toggle RR", "Tog Defects", toggle_defects);
create_button("Toggle RR", "Congestion", toggle_congestion);
if (crit_path_button_enabled) {
create_button("Congestion", "Crit. Path", highlight_crit_path);
}
} else if (pic_on_screen_val == PLACEMENT && pic_on_screen == ROUTING) {
destroy_button("Toggle RR");
destroy_button("Congestion");
if (crit_path_button_enabled) {
destroy_button("Crit. Path");
}
} else if (pic_on_screen_val == ROUTING
&& pic_on_screen == NO_PICTURE) {
create_button("Window", "Toggle Nets", toggle_nets);
create_button("Toggle Nets", "Toggle RR", toggle_rr);
create_button("Toggle RR", "Tog Defects", toggle_defects);
create_button("Tog Defects", "Congestion", toggle_congestion);
if (crit_path_button_enabled) {
create_button("Congestion", "Crit. Path", highlight_crit_path);
}
}
}
/* Save the main message. */
my_strncpy(default_message, msg, BUFSIZE);
pic_on_screen = pic_on_screen_val;
update_message(msg);
drawscreen();
if (priority >= gr_automode) {
event_loop(highlight_blocks, NULL, NULL, drawscreen);
} else {
flushinput();
}
}
static void drawscreen() {
/* This is the screen redrawing routine that event_loop assumes exists. *
* It erases whatever is on screen, then calls redraw_screen to redraw *
* it. */
clearscreen();
redraw_screen();
}
static void redraw_screen() {
/* The screen redrawing routine called by drawscreen and *
* highlight_blocks. Call this routine instead of drawscreen if *
* you know you don't need to erase the current graphics, and want *
* to avoid a screen "flash". */
setfontsize(14); /* UDSD Modification by WMF */
if (pic_on_screen == PLACEMENT) {
drawplace();
if (show_nets) {
drawnets();
}
} else { /* ROUTING on screen */
drawplace();
if (show_nets) {
drawroute(ALL_NETS);
} else {
draw_rr();
}
if (show_congestion) {
draw_congestion();
}
}
}
static void toggle_nets(void (*drawscreen_ptr)(void)) {
/* Enables/disables drawing of nets when a the user clicks on a button. *
* Also disables drawing of routing resources. See graphics.c for details *
* of how buttons work. */
show_nets = (show_nets == FALSE) ? TRUE : FALSE;
draw_rr_toggle = DRAW_NO_RR;
show_congestion = FALSE;
update_message(default_message);
drawscreen_ptr();
}
static void toggle_rr(void (*drawscreen_ptr)(void)) {
/* Cycles through the options for viewing the routing resources available *
* in an FPGA. If a routing isn't on screen, the routing graph hasn't been *
* built, and this routine doesn't switch the view. Otherwise, this routine *
* switches to the routing resource view. Clicking on the toggle cycles *
* through the options: DRAW_NO_RR, DRAW_ALL_RR, DRAW_ALL_BUT_BUFFERS_RR, *
* DRAW_NODES_AND_SBOX_RR, and DRAW_NODES_RR. */
draw_rr_toggle = (enum e_draw_rr_toggle) (((int)draw_rr_toggle + 1) % ((int)DRAW_RR_TOGGLE_MAX));
show_nets = FALSE;
show_congestion = FALSE;
update_message(default_message);
drawscreen_ptr();
}
static void toggle_defects(void (*drawscreen_ptr)(void)) {
show_defects = (show_defects == FALSE) ? TRUE : FALSE;
update_message(default_message);
drawscreen_ptr();
}
static void toggle_congestion(void (*drawscreen_ptr)(void)) {
/* Turns the congestion display on and off. */
char msg[BUFSIZE];
int inode, num_congested;
show_nets = FALSE;
draw_rr_toggle = DRAW_NO_RR;
show_congestion = (show_congestion == FALSE) ? TRUE : FALSE;
if (!show_congestion) {
update_message(default_message);
} else {
num_congested = 0;
for (inode = 0; inode < num_rr_nodes; inode++) {
if (rr_node[inode].occ > rr_node[inode].capacity) {
num_congested++;
}
}
sprintf(msg, "%d routing resources are overused.", num_congested);
update_message(msg);
}
drawscreen_ptr();
}
static void highlight_crit_path(void (*drawscreen_ptr)(void)) {
/* Highlights all the blocks and nets on the critical path. */
t_linked_int *critical_path_head, *critical_path_node;
int inode, iblk, inet, num_nets_seen;
static int nets_to_highlight = 1;
char msg[BUFSIZE];
if (nets_to_highlight == 0) { /* Clear the display of all highlighting. */
nets_to_highlight = 1;
deselect_all();
update_message(default_message);
drawscreen_ptr();
return;
}
critical_path_head = allocate_and_load_critical_path();
critical_path_node = critical_path_head;
num_nets_seen = 0;
while (critical_path_node != NULL) {
inode = critical_path_node->data;
get_tnode_block_and_output_net(inode, &iblk, &inet);
if (num_nets_seen == nets_to_highlight) { /* Last block */
block_color[iblk] = MAGENTA;
} else if (num_nets_seen == nets_to_highlight - 1) { /* 2nd last block */
block_color[iblk] = YELLOW;
} else if (num_nets_seen < nets_to_highlight) { /* Earlier block */
block_color[iblk] = DARKGREEN;
}
if (inet != OPEN) {
num_nets_seen++;
if (num_nets_seen < nets_to_highlight) { /* First nets. */
net_color[inet] = DARKGREEN;
} else if (num_nets_seen == nets_to_highlight) {
net_color[inet] = CYAN; /* Last (new) net. */
}
}
critical_path_node = critical_path_node->next;
}
if (nets_to_highlight == num_nets_seen) {
nets_to_highlight = 0;
sprintf(msg, "All %d nets on the critical path highlighted.",
num_nets_seen);
} else {
sprintf(msg, "First %d nets on the critical path highlighted.",
nets_to_highlight);
nets_to_highlight++;
}
free_int_list(&critical_path_head);
update_message(msg);
drawscreen_ptr();
}
void alloc_draw_structs(void) {
/* Allocate the structures needed to draw the placement and routing. Set *
* up the default colors for blocks and nets. */
tile_x = (float *) my_malloc((nx + 2) * sizeof(float));
tile_y = (float *) my_malloc((ny + 2) * sizeof(float));
net_color = (enum color_types *) my_malloc(
num_nets * sizeof(enum color_types));
block_color = (enum color_types *) my_malloc(
num_blocks * sizeof(enum color_types));
x_rr_node_left = (float *) my_malloc(num_rr_nodes * sizeof(float));
x_rr_node_right = (float *) my_malloc(num_rr_nodes * sizeof(float));
y_rr_node_top = (float *) my_malloc(num_rr_nodes * sizeof(float));
y_rr_node_bottom = (float *) my_malloc(num_rr_nodes * sizeof(float));
rr_node_color = (enum color_types *) my_malloc(
num_rr_nodes * sizeof(enum color_types));
deselect_all(); /* Set initial colors */
}
void free_draw_structs(void) {
/* Free everything allocated by alloc_draw_structs. Called after close_graphics() *
* in vpr_api.c.
*
* For safety, set all the array pointers to NULL in case any data
* structure gets freed twice. */
free(tile_x);
tile_x = NULL;
free(tile_y);
tile_y = NULL;
free(net_color);
net_color = NULL;
free(block_color);
block_color = NULL;
free(x_rr_node_left);
x_rr_node_left = NULL;
free(x_rr_node_right);
x_rr_node_right = NULL;
free(y_rr_node_top);
y_rr_node_top = NULL;
free(y_rr_node_bottom);
y_rr_node_bottom = NULL;
free(rr_node_color);
rr_node_color = NULL;
}
void init_draw_coords(float width_val) {
/* Load the arrays containing the left and bottom coordinates of the clbs *
* forming the FPGA. tile_width_val sets the width and height of a drawn *
* clb. */
int i;
int j;
if (!show_graphics)
return; /* -nodisp was selected. */
if (num_rr_nodes != old_num_rr_nodes) {
x_rr_node_left = (float *) my_realloc(x_rr_node_left,
(num_rr_nodes) * sizeof(float));
x_rr_node_right = (float *) my_realloc(x_rr_node_right,
(num_rr_nodes) * sizeof(float));
y_rr_node_top = (float *) my_realloc(y_rr_node_top,
(num_rr_nodes) * sizeof(float));
y_rr_node_bottom = (float *) my_realloc(y_rr_node_bottom,
(num_rr_nodes) * sizeof(float));
rr_node_color = (enum color_types *) my_realloc(rr_node_color,
(num_rr_nodes) * sizeof(enum color_types));
for (i = 0; i < num_rr_nodes; i++) {
x_rr_node_left[i] = -1;
x_rr_node_right[i] = -1;
y_rr_node_top[i] = -1;
y_rr_node_bottom[i] = -1;
rr_node_color[i] = BLACK;
}
}
tile_width = width_val;
pin_size = 0.3;
for (i = 0; i < num_types; ++i) {
pin_size = std::min(pin_size,
(tile_width / (4.0F * type_descriptors[i].num_pins)));
}
j = 0;
for (i = 0; i < (nx + 1); i++) {
tile_x[i] = (i * tile_width) + j;
j += chan_width_y[i] + 1; /* N wires need N+1 units of space */
}
tile_x[nx + 1] = ((nx + 1) * tile_width) + j;
j = 0;
for (i = 0; i < (ny + 1); ++i) {
tile_y[i] = (i * tile_width) + j;
j += chan_width_x[i] + 1;
}
tile_y[ny + 1] = ((ny + 1) * tile_width) + j;
init_world(0.0, tile_y[ny + 1] + tile_width, tile_x[nx + 1] + tile_width,
0.0);
}
static void drawplace(void) {
/* Draws the blocks placed on the proper clbs. Occupied blocks are darker colours *
* while empty ones are lighter colours and have a dashed border. */
float sub_tile_step;
float x1, y1, x2, y2;
int i, j, k, bnum;
int num_sub_tiles;
int height;
setlinewidth(0);
for (i = 0; i <= (nx + 1); i++) {
for (j = 0; j <= (ny + 1); j++) {
/* Only the first block of a group should control drawing */
if (grid[i][j].offset > 0)
continue;
/* Don't draw corners */
if (((i < 1) || (i > nx)) && ((j < 1) || (j > ny)))
continue;
num_sub_tiles = grid[i][j].type->capacity;
sub_tile_step = tile_width / num_sub_tiles;
height = grid[i][j].type->height;
if (num_sub_tiles < 1) {
setcolor(BLACK);
setlinestyle(DASHED);
drawrect(tile_x[i], tile_y[j], tile_x[i] + tile_width,
tile_y[j] + tile_width);
draw_x(tile_x[i] + (tile_width / 2),
tile_y[j] + (tile_width / 2), (tile_width / 2));
}
for (k = 0; k < num_sub_tiles; ++k) {
/* Graphics will look unusual for multiple height and capacity */
assert(height == 1 || num_sub_tiles == 1);
/* Get coords of current sub_tile */
if ((i < 1) || (i > nx)) { /* left and right fringes */
x1 = tile_x[i];
y1 = tile_y[j] + (k * sub_tile_step);
x2 = x1 + tile_width;
y2 = y1 + sub_tile_step;
} else if ((j < 1) || (j > ny)) { /* top and bottom fringes */
x1 = tile_x[i] + (k * sub_tile_step);
y1 = tile_y[j];
x2 = x1 + sub_tile_step;
y2 = y1 + tile_width;
} else {
assert(num_sub_tiles <= 1);
/* Need to change draw code to support */
x1 = tile_x[i];
y1 = tile_y[j];
x2 = x1 + tile_width;
y2 = tile_y[j + height - 1] + tile_width;
}
/* Look at the tile at start of large block */
bnum = grid[i][j].blocks[k];
/* Draw background */
if (bnum != EMPTY) {
setcolor(block_color[bnum]);
fillrect(x1, y1, x2, y2);
} else {
/* colour empty blocks a particular colour depending on type */
if (grid[i][j].type->index < 3) {
setcolor(WHITE);
} else if (grid[i][j].type->index < 3 + MAX_BLOCK_COLOURS) {
setcolor(BISQUE + grid[i][j].type->index - 3);
} else {
setcolor(BISQUE + MAX_BLOCK_COLOURS - 1);
}
fillrect(x1, y1, x2, y2);
}
setcolor(BLACK);
setlinestyle((EMPTY == bnum) ? DASHED : SOLID);
drawrect(x1, y1, x2, y2);
/* Draw text if the space has parts of the netlist */
if (bnum != EMPTY) {
drawtext((x1 + x2) / 2.0, (y1 + y2) / 2.0, block[bnum].name,
tile_width);
}
/* Draw text for block type so that user knows what block */
if (grid[i][j].offset == 0) {
if (i > 0 && i <= nx && j > 0 && j <= ny) {
drawtext((x1 + x2) / 2.0, y1 + (tile_width / 4.0),
grid[i][j].type->name, tile_width);
}
}
}
}
}
}
static void drawnets(void) {
/* This routine draws the nets on the placement. The nets have not *
* yet been routed, so we just draw a chain showing a possible path *
* for each net. This gives some idea of future congestion. */
int inet, ipin, b1, b2;
float x1, y1, x2, y2;
setlinestyle(SOLID);
setlinewidth(0);
/* Draw the net as a star from the source to each sink. Draw from centers of *
* blocks (or sub blocks in the case of IOs). */
for (inet = 0; inet < num_nets; inet++) {
if (clb_net[inet].is_global)
continue; /* Don't draw global nets. */
setcolor(net_color[inet]);
b1 = clb_net[inet].node_block[0]; /* The DRIVER */
get_block_center(b1, &x1, &y1);
for (ipin = 1; ipin < (clb_net[inet].num_sinks + 1); ipin++) {
b2 = clb_net[inet].node_block[ipin];
get_block_center(b2, &x2, &y2);
drawline(x1, y1, x2, y2);
/* Uncomment to draw a chain instead of a star. */
/* x1 = x2; */
/* y1 = y2; */
}
}
}
static void get_block_center(int bnum, float *x, float *y) {
/* This routine finds the center of block bnum in the current placement, *
* and returns it in *x and *y. This is used in routine shownets. */
int i, j, k;
float sub_tile_step;
i = block[bnum].x;
j = block[bnum].y;
k = block[bnum].z;
sub_tile_step = tile_width / block[bnum].type->capacity;
if ((i < 1) || (i > nx)) { /* Left and right fringe */
*x = tile_x[i] + (sub_tile_step * (k + 0.5));
} else {
*x = tile_x[i] + (tile_width / 2.0);
}
if ((j < 1) || (j > ny)) { /* Top and bottom fringe */
*y = tile_y[j] + (sub_tile_step * (k + 0.5));
} else {
*y = tile_y[j] + (tile_width / 2.0);
}
}
static void draw_congestion(void) {
/* Draws all the overused routing resources (i.e. congestion) in RED. */
int inode, itrack;
setcolor(RED);
setlinewidth(2);
for (inode = 0; inode < num_rr_nodes; inode++) {
if (rr_node[inode].occ > rr_node[inode].capacity) {
switch (rr_node[inode].type) {
case CHANX:
itrack = rr_node[inode].ptc_num;
draw_rr_chanx(inode, itrack);
break;
case CHANY:
itrack = rr_node[inode].ptc_num;
draw_rr_chany(inode, itrack);
break;
case IPIN:
case OPIN:
draw_rr_pin(inode, RED);
break;
default:
break;
}
}
}
}
void draw_rr(void) {
/* Draws the routing resources that exist in the FPGA, if the user wants *
* them drawn. */
int inode, itrack;
if (draw_rr_toggle == DRAW_NO_RR) {
setlinewidth(3);
drawroute(HIGHLIGHTED);
setlinewidth(0);
return;
}
setlinestyle(SOLID);
setlinewidth(0);
for (inode = 0; inode < num_rr_nodes; inode++) {
switch (rr_node[inode].type) {
case SOURCE:
case SINK:
break; /* Don't draw. */
case CHANX:
if (show_defects && (rr_node[inode].capacity <= 0))
setcolor(RED);
else
setcolor(BLACK);
if (show_defects && (rr_node[inode].occ > 0))
setcolor(CYAN);
itrack = rr_node[inode].ptc_num;
draw_rr_chanx(inode, itrack);
draw_rr_edges(inode);
break;
case CHANY:
if (show_defects && (rr_node[inode].capacity <= 0))
setcolor(RED);
else
setcolor(BLACK);
if (show_defects && (rr_node[inode].occ > 0))
setcolor(CYAN);
itrack = rr_node[inode].ptc_num;
draw_rr_chany(inode, itrack);
draw_rr_edges(inode);
break;
case IPIN:
if (show_defects) {
if (rr_node[inode].capacity < 0)
draw_rr_pin(inode, RED);
else if (rr_node[inode].occ > 0)
draw_rr_pin(inode, CYAN);
else
draw_rr_pin(inode, BLACK);
} else
draw_rr_pin(inode, BLUE);
break;
case OPIN:
if (show_defects) {
if (rr_node[inode].capacity < 0)
draw_rr_pin(inode, RED);
else if (rr_node[inode].occ > 0)
draw_rr_pin(inode, CYAN);
else
draw_rr_pin(inode, BLACK);
setcolor(BLACK);
} else {
draw_rr_pin(inode, RED);
setcolor(RED);
}
setcolor(RED);
draw_rr_edges(inode);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "in draw_rr: Unexpected rr_node type: %d.\n", rr_node[inode].type);
exit(1);
}
}
setlinewidth(3);
drawroute(HIGHLIGHTED);
setlinewidth(0);
}
static void draw_rr_chanx(int inode, int itrack) {
/* Draws an x-directed channel segment. */
enum {
BUFFSIZE = 80
};
float x1, x2, y;
float y1, y2; /* UDSD by AY */
int k; /* UDSD by AY */
char str[BUFFSIZE];
int savecolor;
/* Track 0 at bottom edge, closest to "owning" clb. */
x1 = tile_x[rr_node[inode].xlow];
x2 = tile_x[rr_node[inode].xhigh] + tile_width;
y = tile_y[rr_node[inode].ylow] + tile_width + 1.0 + itrack;
x_rr_node_left[inode] = x1;
x_rr_node_right[inode] = x2;
y_rr_node_bottom[inode] = y - line_fuz;
y_rr_node_top[inode] = y + line_fuz;
if (rr_node_color[inode] != BLACK) {
savecolor = getcolor();
setcolor(rr_node_color[inode]);
setlinewidth(3);
drawline(x1, y, x2, y);
setlinewidth(0);
setcolor(savecolor);
} else {
drawline(x1, y, x2, y);
}
/* UDSD by AY Start */
y1 = y - 0.25;
y2 = y + 0.25;
if (rr_node[inode].direction == INC_DIRECTION) {
setlinewidth(2);
setcolor(YELLOW);
drawline(x1, y1, x1, y2); /* Draw a line at start of wire to indicate mux */
/* Mux balence numbers */
setcolor(BLACK);
sprintf(str, "%d", rr_node[inode].fan_in);
drawtext(x1, y, str, 5);
setcolor(BLACK);
setlinewidth(0);
draw_triangle_along_line(x2 - 0.15, y, x1, x2, y, y);
setcolor(LIGHTGREY);
/* TODO: this looks odd, why does it ignore final block? does this mean nothing appears with L=1 ? */
for (k = rr_node[inode].xlow; k < rr_node[inode].xhigh; k++) {
x2 = tile_x[k] + tile_width;
draw_triangle_along_line(x2 - 0.15, y, x1, x2, y, y);
x2 = tile_x[k + 1];
draw_triangle_along_line(x2 + 0.15, y, x1, x2, y, y);
}
setcolor(BLACK);
} else if (rr_node[inode].direction == DEC_DIRECTION) {
setlinewidth(2);
setcolor(YELLOW);
drawline(x2, y1, x2, y2);
/* Mux balance numbers */
setcolor(BLACK);
sprintf(str, "%d", rr_node[inode].fan_in);
drawtext(x2, y, str, 5);
setlinewidth(0);
draw_triangle_along_line(x1 + 0.15, y, x2, x1, y, y);
setcolor(LIGHTGREY);
for (k = rr_node[inode].xhigh; k > rr_node[inode].xlow; k--) {
x1 = tile_x[k];
draw_triangle_along_line(x1 + 0.15, y, x2, x1, y, y);
x1 = tile_x[k - 1] + tile_width;
draw_triangle_along_line(x1 - 0.15, y, x2, x1, y, y);
}
setcolor(BLACK);
}
/* UDSD by AY End */
}
static void draw_rr_chany(int inode, int itrack) {
/* Draws a y-directed channel segment. */
enum {
BUFFSIZE = 80
};
float x, y1, y2;
float x1, x2; /* UDSD by AY */
int k; /* UDSD by AY */
char str[BUFFSIZE];
int savecolor;
/* Track 0 at left edge, closest to "owning" clb. */
x = tile_x[rr_node[inode].xlow] + tile_width + 1. + itrack;
y1 = tile_y[rr_node[inode].ylow];
y2 = tile_y[rr_node[inode].yhigh] + tile_width;
x_rr_node_left[inode] = x - line_fuz;
x_rr_node_right[inode] = x + line_fuz;
y_rr_node_bottom[inode] = y1;
y_rr_node_top[inode] = y2;
if (rr_node_color[inode] != BLACK) {
savecolor = getcolor();
setcolor(rr_node_color[inode]);
setlinewidth(3);
drawline(x, y1, x, y2);
setlinewidth(0);
setcolor(savecolor);
} else {
drawline(x, y1, x, y2);
}
/* UDSD by AY Start */
x1 = x - 0.25;
x2 = x + 0.25;
if (rr_node[inode].direction == INC_DIRECTION) {
setlinewidth(2);
setcolor(YELLOW);
drawline(x1, y1, x2, y1);
/* UDSD Modifications by WMF Begin */
setcolor(BLACK);
sprintf(str, "%d", rr_node[inode].fan_in);
drawtext(x, y1, str, 5);
setcolor(BLACK);
/* UDSD Modifications by WMF End */
setlinewidth(0);
draw_triangle_along_line(x, y2 - 0.15, x, x, y1, y2);
setcolor(LIGHTGREY);
for (k = rr_node[inode].ylow; k < rr_node[inode].yhigh; k++) {
y2 = tile_y[k] + tile_width;
draw_triangle_along_line(x, y2 - 0.15, x, x, y1, y2);
y2 = tile_y[k + 1];
draw_triangle_along_line(x, y2 + 0.15, x, x, y1, y2);
}
setcolor(BLACK);
} else if (rr_node[inode].direction == DEC_DIRECTION) {
setlinewidth(2);
setcolor(YELLOW);
drawline(x1, y2, x2, y2);
/* UDSD Modifications by WMF Begin */
setcolor(BLACK);
sprintf(str, "%d", rr_node[inode].fan_in);
drawtext(x, y2, str, 5);
setcolor(BLACK);
/* UDSD Modifications by WMF End */
setlinewidth(0);
draw_triangle_along_line(x, y1 + 0.15, x, x, y2, y1);
setcolor(LIGHTGREY);
for (k = rr_node[inode].yhigh; k > rr_node[inode].ylow; k--) {
y1 = tile_y[k];
draw_triangle_along_line(x, y1 + 0.15, x, x, y2, y1);
y1 = tile_y[k - 1] + tile_width;
draw_triangle_along_line(x, y1 - 0.15, x, x, y2, y1);
}
setcolor(BLACK);
}
/* UDSD by AY End */
}
static void draw_rr_edges(int inode) {
/* Draws all the edges that the user wants shown between inode and what it *
* connects to. inode is assumed to be a CHANX, CHANY, or OPIN. */
t_rr_type from_type, to_type;
int iedge, to_node, from_ptc_num, to_ptc_num;
short switch_type;
boolean defective = FALSE;
from_type = rr_node[inode].type;
if ((draw_rr_toggle == DRAW_NODES_RR)
|| (draw_rr_toggle == DRAW_NODES_AND_SBOX_RR && from_type == OPIN)) {
return; /* Nothing to draw. */
}
from_ptc_num = rr_node[inode].ptc_num;
for (iedge = 0; iedge < rr_node[inode].num_edges; iedge++) {
to_node = rr_node[inode].edges[iedge];
to_type = rr_node[to_node].type;
to_ptc_num = rr_node[to_node].ptc_num;
if (show_defects)
defective = (boolean)(switch_inf[rr_node[inode].switches[iedge]].R < 0);
switch (from_type) {
case OPIN:
switch (to_type) {
case CHANX:
case CHANY:
if (show_defects) {
if (defective)
setcolor(RED);
else
setcolor(BLACK);
} else
setcolor(RED);
draw_pin_to_chan_edge(inode, to_node);
break;
case IPIN:
setcolor(RED);
draw_pin_to_pin(inode, to_node);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n",
inode, from_type, to_node, to_type);
exit(1);
break;
}
break;
case CHANX: /* from_type */
switch (to_type) {
case IPIN:
if (draw_rr_toggle == DRAW_NODES_AND_SBOX_RR) {
break;
}
if (show_defects) {
if (defective)
setcolor(RED);
else
setcolor(BLACK);
} else
setcolor(BLUE);
draw_pin_to_chan_edge(to_node, inode);
break;
case CHANX:
if (show_defects) {
if (defective)
setcolor(RED);
else
setcolor(BLACK);
} else
setcolor(DARKGREEN);
switch_type = rr_node[inode].switches[iedge];
draw_chanx_to_chanx_edge(inode, from_ptc_num, to_node,
to_ptc_num, switch_type);
break;
case CHANY:
if (show_defects) {
if (defective)
setcolor(RED);
else
setcolor(BLACK);
} else
setcolor(DARKGREEN);
switch_type = rr_node[inode].switches[iedge];
draw_chanx_to_chany_edge(inode, from_ptc_num, to_node,
to_ptc_num, FROM_X_TO_Y, switch_type);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n",
inode, from_type, to_node, to_type);
exit(1);
break;
}
break;
case CHANY: /* from_type */
switch (to_type) {
case IPIN:
if (draw_rr_toggle == DRAW_NODES_AND_SBOX_RR) {
break;
}
if (show_defects) {
if (defective)
setcolor(RED);
else
setcolor(BLACK);
} else
setcolor(BLUE);
draw_pin_to_chan_edge(to_node, inode);
break;
case CHANX:
if (show_defects) {
if (defective)
setcolor(RED);
else
setcolor(BLACK);
} else
setcolor(DARKGREEN);
switch_type = rr_node[inode].switches[iedge];
draw_chanx_to_chany_edge(to_node, to_ptc_num, inode,
from_ptc_num, FROM_Y_TO_X, switch_type);
break;
case CHANY:
if (show_defects) {
if (defective)
setcolor(RED);
else
setcolor(BLACK);
} else
setcolor(DARKGREEN);
switch_type = rr_node[inode].switches[iedge];
draw_chany_to_chany_edge(inode, from_ptc_num, to_node,
to_ptc_num, switch_type);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n",
inode, from_type, to_node, to_type);
exit(1);
break;
}
break;
default: /* from_type */
vpr_printf(TIO_MESSAGE_ERROR, "draw_rr_edges called with node %d of type %d.\n",
inode, from_type);
exit(1);
break;
}
} /* End of for each edge loop */
}
static void draw_x(float x, float y, float size) {
/* Draws an X centered at (x,y). The width and height of the X are each *
* 2 * size. */
drawline(x - size, y + size, x + size, y - size);
drawline(x - size, y - size, x + size, y + size);
}
/* UDSD Modifications by WMF: Thank God Andy fixed this. */
static void draw_chanx_to_chany_edge(int chanx_node, int chanx_track,
int chany_node, int chany_track, enum e_edge_dir edge_dir,
short switch_type) {
/* Draws an edge (SBOX connection) between an x-directed channel and a *
* y-directed channel. */
float x1, y1, x2, y2;
int chanx_y, chany_x, chanx_xlow, chany_ylow;
chanx_y = rr_node[chanx_node].ylow;
chanx_xlow = rr_node[chanx_node].xlow;
chany_x = rr_node[chany_node].xlow;
chany_ylow = rr_node[chany_node].ylow;
/* (x1,y1): point on CHANX segment, (x2,y2): point on CHANY segment. */
y1 = tile_y[chanx_y] + tile_width + 1. + chanx_track;
x2 = tile_x[chany_x] + tile_width + 1. + chany_track;
if (chanx_xlow <= chany_x) { /* Can draw connection going right */
x1 = tile_x[chany_x] + tile_width;
/* UDSD by AY Start */
if (rr_node[chanx_node].direction != BI_DIRECTION) {
if (edge_dir == FROM_X_TO_Y) {
if ((chanx_track % 2) == 1) { /* UDSD Modifications by WMF: If dec wire, then going left */
x1 = tile_x[chany_x + 1];
}
}
}
/* UDSD by AY End */
} else { /* Must draw connection going left. */
x1 = tile_x[chanx_xlow];
}
if (chany_ylow <= chanx_y) { /* Can draw connection going up. */
y2 = tile_y[chanx_y] + tile_width;
/* UDSD by AY Start */
if (rr_node[chany_node].direction != BI_DIRECTION) {
if (edge_dir == FROM_Y_TO_X) {
if ((chany_track % 2) == 1) { /* UDSD Modifications by WMF: If dec wire, then going down */
y2 = tile_y[chanx_y + 1];
}
}
}
/* UDSD by AY End */
} else { /* Must draw connection going down. */
y2 = tile_y[chany_ylow];
}
drawline(x1, y1, x2, y2);
if (draw_rr_toggle != DRAW_ALL_RR)
return;
if (edge_dir == FROM_X_TO_Y)
draw_rr_switch(x1, y1, x2, y2, switch_inf[switch_type].buffered);
else
draw_rr_switch(x2, y2, x1, y1, switch_inf[switch_type].buffered);
}
static void draw_chanx_to_chanx_edge(int from_node, int from_track, int to_node,
int to_track, short switch_type) {
/* Draws a connection between two x-channel segments. Passing in the track *
* numbers allows this routine to be used for both rr_graph and routing *
* drawing. */
float x1, x2, y1, y2;
int from_y, to_y, from_xlow, to_xlow, from_xhigh, to_xhigh;
from_y = rr_node[from_node].ylow;
from_xlow = rr_node[from_node].xlow;
from_xhigh = rr_node[from_node].xhigh;
to_y = rr_node[to_node].ylow;
to_xlow = rr_node[to_node].xlow;
to_xhigh = rr_node[to_node].xhigh;
/* (x1, y1) point on from_node, (x2, y2) point on to_node. */
y1 = tile_y[from_y] + tile_width + 1 + from_track;
y2 = tile_y[to_y] + tile_width + 1 + to_track;
if (to_xhigh < from_xlow) { /* From right to left */
/* UDSD Note by WMF: could never happen for INC wires, unless U-turn. For DEC
* wires this handles well */
x1 = tile_x[from_xlow];
x2 = tile_x[to_xhigh] + tile_width;
} else if (to_xlow > from_xhigh) { /* From left to right */
/* UDSD Note by WMF: could never happen for DEC wires, unless U-turn. For INC
* wires this handles well */
x1 = tile_x[from_xhigh] + tile_width;
x2 = tile_x[to_xlow];
}
/* Segments overlap in the channel. Figure out best way to draw. Have to *
* make sure the drawing is symmetric in the from rr and to rr so the edges *
* will be drawn on top of each other for bidirectional connections. */
/* UDSD Modification by WMF Begin */
else {
if (rr_node[to_node].direction != BI_DIRECTION) {
/* must connect to to_node's wire beginning at x2 */
if (to_track % 2 == 0) { /* INC wire starts at leftmost edge */
assert(from_xlow < to_xlow);
x2 = tile_x[to_xlow];
/* since no U-turns from_track must be INC as well */
x1 = tile_x[to_xlow - 1] + tile_width;
} else { /* DEC wire starts at rightmost edge */
assert(from_xhigh > to_xhigh);
x2 = tile_x[to_xhigh] + tile_width;
x1 = tile_x[to_xhigh + 1];
}
} else {
if (to_xlow < from_xlow) { /* Draw from left edge of one to other */
x1 = tile_x[from_xlow];
x2 = tile_x[from_xlow - 1] + tile_width;
} else if (from_xlow < to_xlow) {
x1 = tile_x[to_xlow - 1] + tile_width;
x2 = tile_x[to_xlow];
} /* The following then is executed when from_xlow == to_xlow */
else if (to_xhigh > from_xhigh) { /* Draw from right edge of one to other */
x1 = tile_x[from_xhigh] + tile_width;
x2 = tile_x[from_xhigh + 1];
} else if (from_xhigh > to_xhigh) {
x1 = tile_x[to_xhigh + 1];
x2 = tile_x[to_xhigh] + tile_width;
} else { /* Complete overlap: start and end both align. Draw outside the sbox */
x1 = tile_x[from_xlow];
x2 = tile_x[from_xlow] + tile_width;
}
}
}
/* UDSD Modification by WMF End */
drawline(x1, y1, x2, y2);
if (draw_rr_toggle == DRAW_ALL_RR)
draw_rr_switch(x1, y1, x2, y2, switch_inf[switch_type].buffered);
}
static void draw_chany_to_chany_edge(int from_node, int from_track, int to_node,
int to_track, short switch_type) {
/* Draws a connection between two y-channel segments. Passing in the track *
* numbers allows this routine to be used for both rr_graph and routing *
* drawing. */
float x1, x2, y1, y2;
int from_x, to_x, from_ylow, to_ylow, from_yhigh, to_yhigh;
from_x = rr_node[from_node].xlow;
from_ylow = rr_node[from_node].ylow;
from_yhigh = rr_node[from_node].yhigh;
to_x = rr_node[to_node].xlow;
to_ylow = rr_node[to_node].ylow;
to_yhigh = rr_node[to_node].yhigh;
/* (x1, y1) point on from_node, (x2, y2) point on to_node. */
x1 = tile_x[from_x] + tile_width + 1 + from_track;
x2 = tile_x[to_x] + tile_width + 1 + to_track;
if (to_yhigh < from_ylow) { /* From upper to lower */
y1 = tile_y[from_ylow];
y2 = tile_y[to_yhigh] + tile_width;
} else if (to_ylow > from_yhigh) { /* From lower to upper */
y1 = tile_y[from_yhigh] + tile_width;
y2 = tile_y[to_ylow];
}
/* Segments overlap in the channel. Figure out best way to draw. Have to *
* make sure the drawing is symmetric in the from rr and to rr so the edges *
* will be drawn on top of each other for bidirectional connections. */
/* UDSD Modification by WMF Begin */
else {
if (rr_node[to_node].direction != BI_DIRECTION) {
if (to_track % 2 == 0) { /* INC wire starts at bottom edge */
assert(from_ylow < to_ylow);
y2 = tile_y[to_ylow];
/* since no U-turns from_track must be INC as well */
y1 = tile_y[to_ylow - 1] + tile_width;
} else { /* DEC wire starts at top edge */
if (!(from_yhigh > to_yhigh)) {
vpr_printf(TIO_MESSAGE_INFO, "from_yhigh (%d) !> to_yhigh (%d).\n",
from_yhigh, to_yhigh);
vpr_printf(TIO_MESSAGE_INFO, "from is (%d, %d) to (%d, %d) track %d.\n",
rr_node[from_node].xhigh, rr_node[from_node].yhigh,
rr_node[from_node].xlow, rr_node[from_node].ylow,
rr_node[from_node].ptc_num);
vpr_printf(TIO_MESSAGE_INFO, "to is (%d, %d) to (%d, %d) track %d.\n",
rr_node[to_node].xhigh, rr_node[to_node].yhigh,
rr_node[to_node].xlow, rr_node[to_node].ylow,
rr_node[to_node].ptc_num);
exit(1);
}
y2 = tile_y[to_yhigh] + tile_width;
y1 = tile_y[to_yhigh + 1];
}
} else {
if (to_ylow < from_ylow) { /* Draw from bottom edge of one to other. */
y1 = tile_y[from_ylow];
y2 = tile_y[from_ylow - 1] + tile_width;
} else if (from_ylow < to_ylow) {
y1 = tile_y[to_ylow - 1] + tile_width;
y2 = tile_y[to_ylow];
} else if (to_yhigh > from_yhigh) { /* Draw from top edge of one to other. */
y1 = tile_y[from_yhigh] + tile_width;
y2 = tile_y[from_yhigh + 1];
} else if (from_yhigh > to_yhigh) {
y1 = tile_y[to_yhigh + 1];
y2 = tile_y[to_yhigh] + tile_width;
} else { /* Complete overlap: start and end both align. Draw outside the sbox */
y1 = tile_y[from_ylow];
y2 = tile_y[from_ylow] + tile_width;
}
}
}
/* UDSD Modification by WMF End */
drawline(x1, y1, x2, y2);
if (draw_rr_toggle == DRAW_ALL_RR)
draw_rr_switch(x1, y1, x2, y2, switch_inf[switch_type].buffered);
}
static void draw_rr_switch(float from_x, float from_y, float to_x, float to_y,
boolean buffered) {
/* Draws a buffer (triangle) or pass transistor (circle) on the edge *
* connecting from to to, depending on the status of buffered. The drawing *
* is closest to the from_node, since it reflects the switch type of from. */
const float switch_rad = 0.15;
float magnitude, xcen, ycen, xdelta, ydelta, xbaseline, ybaseline;
float xunit, yunit;
t_point poly[3];
xcen = from_x + (to_x - from_x) / 10.;
ycen = from_y + (to_y - from_y) / 10.;
if (!buffered) { /* Draw a circle for a pass transistor */
drawarc(xcen, ycen, switch_rad, 0., 360.);
} else { /* Buffer */
xdelta = to_x - from_x;
ydelta = to_y - from_y;
magnitude = sqrt(xdelta * xdelta + ydelta * ydelta);
xunit = xdelta / magnitude;
yunit = ydelta / magnitude;
poly[0].x = xcen + xunit * switch_rad;
poly[0].y = ycen + yunit * switch_rad;
xbaseline = xcen - xunit * switch_rad;
ybaseline = ycen - yunit * switch_rad;
/* Recall: perpendicular vector to the unit vector along the switch (xv, yv) *
* is (yv, -xv). */
poly[1].x = xbaseline + yunit * switch_rad;
poly[1].y = ybaseline - xunit * switch_rad;
poly[2].x = xbaseline - yunit * switch_rad;
poly[2].y = ybaseline + xunit * switch_rad;
fillpoly(poly, 3);
}
}
static void draw_rr_pin(int inode, enum color_types color) {
/* Draws an IPIN or OPIN rr_node. Note that the pin can appear on more *
* than one side of a clb. Also note that this routine can change the *
* current color to BLACK. */
int ipin, i, j, iside, ioff;
float xcen, ycen;
char str[BUFSIZE];
t_type_ptr type;
i = rr_node[inode].xlow;
j = rr_node[inode].ylow;
ipin = rr_node[inode].ptc_num;
type = grid[i][j].type;
ioff = grid[i][j].offset;
setcolor(color);
/* TODO: This is where we can hide fringe physical pins and also identify globals (hide, color, show) */
for (iside = 0; iside < 4; iside++) {
if (type->pinloc[grid[i][j].offset][iside][ipin]) { /* Pin exists on this side. */
get_rr_pin_draw_coords(inode, iside, ioff, &xcen, &ycen);
fillrect(xcen - pin_size, ycen - pin_size, xcen + pin_size,
ycen + pin_size);
sprintf(str, "%d", ipin);
setcolor(BLACK);
drawtext(xcen, ycen, str, 2 * pin_size);
setcolor(color);
}
}
}
static void get_rr_pin_draw_coords(int inode, int iside, int ioff, float *xcen,
float *ycen) {
/* Returns the coordinates at which the center of this pin should be drawn. *
* inode gives the node number, and iside gives the side of the clb or pad *
* the physical pin is on. */
int i, j, k, ipin, pins_per_sub_tile;
float offset, xc, yc, step;
t_type_ptr type;
i = rr_node[inode].xlow;
j = rr_node[inode].ylow + ioff; /* Need correct tile of block */
xc = tile_x[i];
yc = tile_y[j];
ipin = rr_node[inode].ptc_num;
type = grid[i][j].type;
pins_per_sub_tile = grid[i][j].type->num_pins / grid[i][j].type->capacity;
k = ipin / pins_per_sub_tile;
/* Since pins numbers go across all sub_tiles in a block in order
* we can treat as a block box for this step */
/* For each sub_tile we need and extra padding space */
step = (float) (tile_width) / (float) (type->num_pins + type->capacity);
offset = (ipin + k + 1) * step;
switch (iside) {
case LEFT:
yc += offset;
break;
case RIGHT:
xc += tile_width;
yc += offset;
break;
case BOTTOM:
xc += offset;
break;
case TOP:
xc += offset;
yc += tile_width;
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "in get_rr_pin_draw_coords: Unexpected iside %d.\n", iside);
exit(1);
break;
}
*xcen = xc;
*ycen = yc;
}
static void drawroute(enum e_draw_net_type draw_net_type) {
/* Draws the nets in the positions fixed by the router. If draw_net_type is *
* ALL_NETS, draw all the nets. If it is HIGHLIGHTED, draw only the nets *
* that are not coloured black (useful for drawing over the rr_graph). */
/* Next free track in each channel segment if routing is GLOBAL */
static int **chanx_track = NULL; /* [1..nx][0..ny] */
static int **chany_track = NULL; /* [0..nx][1..ny] */
int inet, i, j, inode, prev_node, prev_track, itrack;
short switch_type;
struct s_trace *tptr;
t_rr_type rr_type, prev_type;
if (draw_route_type == GLOBAL) {
/* Allocate some temporary storage if it's not already available. */
if (chanx_track == NULL) {
chanx_track = (int **) alloc_matrix(1, nx, 0, ny, sizeof(int));
}
if (chany_track == NULL) {
chany_track = (int **) alloc_matrix(0, nx, 1, ny, sizeof(int));
}
for (i = 1; i <= nx; i++)
for (j = 0; j <= ny; j++)
chanx_track[i][j] = (-1);
for (i = 0; i <= nx; i++)
for (j = 1; j <= ny; j++)
chany_track[i][j] = (-1);
}
setlinestyle(SOLID);
/* Now draw each net, one by one. */
for (inet = 0; inet < num_nets; inet++) {
if (clb_net[inet].is_global) /* Don't draw global nets. */
continue;
if (trace_head[inet] == NULL) /* No routing. Skip. (Allows me to draw */
continue; /* partially complete routes). */
if (draw_net_type == HIGHLIGHTED && net_color[inet] == BLACK)
continue;
setcolor(net_color[inet]);
tptr = trace_head[inet]; /* SOURCE to start */
inode = tptr->index;
rr_type = rr_node[inode].type;
for (;;) {
prev_node = inode;
prev_type = rr_type;
switch_type = tptr->iswitch;
tptr = tptr->next;
inode = tptr->index;
rr_type = rr_node[inode].type;
switch (rr_type) {
case OPIN:
draw_rr_pin(inode, net_color[inet]);
break;
case IPIN:
draw_rr_pin(inode, net_color[inet]);
if(rr_node[prev_node].type == OPIN) {
draw_pin_to_pin(prev_node, inode);
} else {
prev_track = get_track_num(prev_node, chanx_track, chany_track);
draw_pin_to_chan_edge(inode, prev_node);
}
break;
case CHANX:
if (draw_route_type == GLOBAL)
chanx_track[rr_node[inode].xlow][rr_node[inode].ylow]++;
itrack = get_track_num(inode, chanx_track, chany_track);
draw_rr_chanx(inode, itrack);
switch (prev_type) {
case CHANX:
prev_track = get_track_num(prev_node, chanx_track,
chany_track);
draw_chanx_to_chanx_edge(prev_node, prev_track, inode,
itrack, switch_type);
break;
case CHANY:
prev_track = get_track_num(prev_node, chanx_track,
chany_track);
draw_chanx_to_chany_edge(inode, itrack, prev_node,
prev_track, FROM_Y_TO_X, switch_type);
break;
case OPIN:
draw_pin_to_chan_edge(prev_node, inode);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "in drawroute: Unexpected connection from an rr_node of type %d to one of type %d.\n",
prev_type, rr_type);
exit(1);
}
break;
case CHANY:
if (draw_route_type == GLOBAL)
chany_track[rr_node[inode].xlow][rr_node[inode].ylow]++;
itrack = get_track_num(inode, chanx_track, chany_track);
draw_rr_chany(inode, itrack);
switch (prev_type) {
case CHANX:
prev_track = get_track_num(prev_node, chanx_track,
chany_track);
draw_chanx_to_chany_edge(prev_node, prev_track, inode,
itrack, FROM_X_TO_Y, switch_type);
break;
case CHANY:
prev_track = get_track_num(prev_node, chanx_track,
chany_track);
draw_chany_to_chany_edge(prev_node, prev_track, inode,
itrack, switch_type);
break;
case OPIN:
draw_pin_to_chan_edge(prev_node, inode);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "in drawroute: Unexpected connection from an rr_node of type %d to one of type %d.\n",
prev_type, rr_type);
exit(1);
}
break;
default:
break;
}
if (rr_type == SINK) { /* Skip the next segment */
tptr = tptr->next;
if (tptr == NULL)
break;
inode = tptr->index;
rr_type = rr_node[inode].type;
}
} /* End loop over traceback. */
} /* End for (each net) */
}
static int get_track_num(int inode, int **chanx_track, int **chany_track) {
/* Returns the track number of this routing resource node. */
int i, j;
t_rr_type rr_type;
if (draw_route_type == DETAILED)
return (rr_node[inode].ptc_num);
/* GLOBAL route stuff below. */
rr_type = rr_node[inode].type;
i = rr_node[inode].xlow; /* NB: Global rr graphs must have only unit */
j = rr_node[inode].ylow; /* length channel segments. */
switch (rr_type) {
case CHANX:
return (chanx_track[i][j]);
case CHANY:
return (chany_track[i][j]);
default:
vpr_printf(TIO_MESSAGE_ERROR, "in get_track_num: Unexpected node type %d for node %d.\n", rr_type, inode);
exit(1);
}
}
static void highlight_nets(char *message) {
int inet;
struct s_trace *tptr;
for (inet = 0; inet < num_nets; inet++) {
for (tptr = trace_head[inet]; tptr != NULL; tptr = tptr->next) {
if (rr_node_color[tptr->index] != BLACK) {
net_color[inet] = rr_node_color[tptr->index];
sprintf(message, "%s || Net:%d %d", message, inet,
trace_head[inet]->index);
break;
}
}
}
update_message(message);
}
static void highlight_rr_nodes(float x, float y) {
int inode;
int hit = 0;
char message[250] = "";
int edge;
if (draw_rr_toggle == DRAW_NO_RR && !show_nets) {
update_message(default_message);
drawscreen();
return;
}
for (inode = 0; inode < num_rr_nodes; inode++) {
if (x >= x_rr_node_left[inode] && x <= x_rr_node_right[inode]
&& y >= y_rr_node_bottom[inode] && y <= y_rr_node_top[inode]) {
t_rr_type rr_type = rr_node[inode].type;
int xlow = rr_node[inode].xlow;
int xhigh = rr_node[inode].xhigh;
int ylow = rr_node[inode].ylow;
int yhigh = rr_node[inode].yhigh;
int ptc_num = rr_node[inode].ptc_num;
rr_node_color[inode] = MAGENTA;
sprintf(message, "%s%s %d: %s (%d,%d) -> (%d,%d) track: %d",
message, (hit ? " | " : ""), inode, name_type[rr_type],
xlow, ylow, xhigh, yhigh, ptc_num);
#ifdef DEBUG
print_rr_node(stdout, rr_node, inode);
#endif
for (edge = 0; edge < rr_node[inode].num_edges; edge++) {
if (rr_node_color[rr_node[inode].edges[edge]] == BLACK
&& rr_node[rr_node[inode].edges[edge]].capacity
> rr_node[rr_node[inode].edges[edge]].occ)
rr_node_color[rr_node[inode].edges[edge]] = GREEN;
else if (rr_node_color[rr_node[inode].edges[edge]] == BLACK
&& rr_node[rr_node[inode].edges[edge]].capacity
== rr_node[rr_node[inode].edges[edge]].occ)
rr_node_color[rr_node[inode].edges[edge]] = BLUE;
}
hit = 1;
}
}
if (!hit) {
update_message(default_message);
drawscreen();
return;
}
if (show_nets) {
highlight_nets(message);
} else
update_message(message);
drawscreen();
}
static void highlight_blocks(float x, float y) {
/* This routine is called when the user clicks in the graphics area. *
* It determines if a clb was clicked on. If one was, it is *
* highlighted in green, it's fanin nets and clbs are highlighted in *
* blue and it's fanout is highlighted in red. If no clb was *
* clicked on (user clicked on white space) any old highlighting is *
* removed. Note that even though global nets are not drawn, their *
* fanins and fanouts are highlighted when you click on a block *
* attached to them. */
int i, j, k, hit, bnum, ipin, netnum, fanblk;
int iclass;
float io_step;
t_type_ptr type;
char msg[BUFSIZE];
deselect_all();
hit = i = j = k = 0;
for (i = 0; i <= (nx + 1) && !hit; i++) {
if (x <= tile_x[i] + tile_width) {
if (x >= tile_x[i]) {
for (j = 0; j <= (ny + 1) && !hit; j++) {
if (grid[i][j].offset != 0)
continue;
type = grid[i][j].type;
if (y <= tile_y[j + type->height - 1] + tile_width) {
if (y >= tile_y[j])
hit = 1;
}
}
}
}
}
i--;
j--;
if (!hit) {
highlight_rr_nodes(x, y);
/* update_message(default_message);
drawscreen(); */
return;
}
type = grid[i][j].type;
hit = 0;
if (EMPTY_TYPE == type) {
update_message(default_message);
drawscreen();
return;
}
/* The user selected the clb at location (i,j). */
io_step = tile_width / type->capacity;
if ((i < 1) || (i > nx)) /* Vertical columns of IOs */
k = (int) ((y - tile_y[j]) / io_step);
else
k = (int) ((x - tile_x[i]) / io_step);
assert(k < type->capacity);
if (grid[i][j].blocks[k] == EMPTY) {
update_message(default_message);
drawscreen();
return;
}
bnum = grid[i][j].blocks[k];
/* Highlight fanin and fanout. */
for (k = 0; k < type->num_pins; k++) { /* Each pin on a CLB */
netnum = block[bnum].nets[k];
if (netnum == OPEN)
continue;
iclass = type->pin_class[k];
if (type->class_inf[iclass].type == DRIVER) { /* Fanout */
net_color[netnum] = RED;
for (ipin = 1; ipin <= clb_net[netnum].num_sinks; ipin++) {
fanblk = clb_net[netnum].node_block[ipin];
block_color[fanblk] = RED;
}
} else { /* This net is fanin to the block. */
net_color[netnum] = BLUE;
fanblk = clb_net[netnum].node_block[0]; /* DRIVER to net */
block_color[fanblk] = BLUE;
}
}
block_color[bnum] = GREEN; /* Selected block. */
sprintf(msg, "Block %d (%s) at (%d, %d) selected.", bnum, block[bnum].name,
i, j);
update_message(msg);
drawscreen(); /* Need to erase screen. */
}
static void deselect_all(void) {
/* Sets the color of all clbs and nets to the default. */
int i;
/* Create some colour highlighting */
for (i = 0; i < num_blocks; i++) {
if (block[i].type->index < 3) {
block_color[i] = LIGHTGREY;
} else if (block[i].type->index < 3 + MAX_BLOCK_COLOURS) {
block_color[i] = (enum color_types) (BISQUE + MAX_BLOCK_COLOURS + block[i].type->index
- 3);
} else {
block_color[i] = (enum color_types) (BISQUE + 2 * MAX_BLOCK_COLOURS - 1);
}
}
for (i = 0; i < num_nets; i++)
net_color[i] = BLACK;
for (i = 0; i < num_rr_nodes; i++)
rr_node_color[i] = BLACK;
}
/* UDSD by AY Start */
static void draw_triangle_along_line(float xend, float yend, float x1, float x2,
float y1, float y2) {
float switch_rad = 0.15;
float xdelta, ydelta;
float magnitude;
float xunit, yunit;
float xbaseline, ybaseline;
t_point poly[3];
xdelta = x2 - x1;
ydelta = y2 - y1;
magnitude = sqrt(xdelta * xdelta + ydelta * ydelta);
xunit = xdelta / magnitude;
yunit = ydelta / magnitude;
poly[0].x = xend + xunit * switch_rad;
poly[0].y = yend + yunit * switch_rad;
xbaseline = xend - xunit * switch_rad;
ybaseline = yend - yunit * switch_rad;
poly[1].x = xbaseline + yunit * switch_rad;
poly[1].y = ybaseline - xunit * switch_rad;
poly[2].x = xbaseline - yunit * switch_rad;
poly[2].y = ybaseline + xunit * switch_rad;
fillpoly(poly, 3);
}
static void draw_pin_to_chan_edge(int pin_node, int chan_node) {
/* This routine draws an edge from the pin_node to the chan_node (CHANX or *
* CHANY). The connection is made to the nearest end of the track instead *
* of perpundicular to the track to symbolize a single-drive connection. *
* If mark_conn is TRUE, draw a box where the pin connects to the track *
* (useful for drawing the rr graph) */
/* TODO: Fix this for global routing, currently for detailed only */
t_rr_type chan_type;
int grid_x, grid_y, pin_num, chan_xlow, chan_ylow, ioff, height;
float x1, x2, y1, y2;
int start, end, i;
int itrack;
float xend, yend;
float draw_pin_off;
enum e_direction direction;
enum e_side iside;
t_type_ptr type;
direction = rr_node[chan_node].direction;
grid_x = rr_node[pin_node].xlow;
grid_y = rr_node[pin_node].ylow;
pin_num = rr_node[pin_node].ptc_num;
chan_type = rr_node[chan_node].type;
itrack = rr_node[chan_node].ptc_num;
type = grid[grid_x][grid_y].type;
ioff = grid[grid_x][grid_y].offset;
/* large block begins at primary tile (offset == 0) */
grid_y = grid_y - ioff;
height = grid[grid_x][grid_y].type->height;
chan_ylow = rr_node[chan_node].ylow;
chan_xlow = rr_node[chan_node].xlow;
start = -1;
end = -1;
switch (chan_type) {
case CHANX:
start = rr_node[chan_node].xlow;
end = rr_node[chan_node].xhigh;
if (is_opin(pin_num, type)) {
if (direction == INC_DIRECTION) {
end = rr_node[chan_node].xlow;
} else if (direction == DEC_DIRECTION) {
start = rr_node[chan_node].xhigh;
}
}
start = std::max(start, grid_x);
end = std::min(end, grid_x); /* Width is 1 always */
assert(end >= start);
/* Make sure we are nearby */
if ((grid_y + height - 1) == chan_ylow) {
iside = TOP;
ioff = height - 1;
draw_pin_off = pin_size;
} else {
assert((grid_y - 1) == chan_ylow);
iside = BOTTOM;
ioff = 0;
draw_pin_off = -pin_size;
}
assert(grid[grid_x][grid_y].type->pinloc[ioff][iside][pin_num]);
get_rr_pin_draw_coords(pin_node, iside, ioff, &x1, &y1);
y1 += draw_pin_off;
y2 = tile_y[rr_node[chan_node].ylow] + tile_width + 1. + itrack;
x2 = x1;
if (is_opin(pin_num, type)) {
if (direction == INC_DIRECTION) {
x2 = tile_x[rr_node[chan_node].xlow];
} else if (direction == DEC_DIRECTION) {
x2 = tile_x[rr_node[chan_node].xhigh] + tile_width;
}
}
break;
case CHANY:
start = rr_node[chan_node].ylow;
end = rr_node[chan_node].yhigh;
if (is_opin(pin_num, type)) {
if (direction == INC_DIRECTION) {
end = rr_node[chan_node].ylow;
} else if (direction == DEC_DIRECTION) {
start = rr_node[chan_node].yhigh;
}
}
start = std::max(start, grid_y);
end = std::min(end, (grid_y + height - 1)); /* Width is 1 always */
assert(end >= start);
/* Make sure we are nearby */
if ((grid_x) == chan_xlow) {
iside = RIGHT;
draw_pin_off = pin_size;
} else {
assert((grid_x - 1) == chan_xlow);
iside = LEFT;
draw_pin_off = -pin_size;
}
for (i = start; i <= end; i++) {
ioff = i - grid_y;
assert(ioff >= 0 && ioff < type->height);
/* Once we find the location, break out, this will leave ioff pointing
* to the correct offset. If an offset is not found, the assertion after
* this will fail. With the correct routing graph, the assertion will not
* be triggered. This also takes care of connecting a wire once to multiple
* physical pins on the same side. */
if (grid[grid_x][grid_y].type->pinloc[ioff][iside][pin_num]) {
break;
}
}
assert(grid[grid_x][grid_y].type->pinloc[ioff][iside][pin_num]);
get_rr_pin_draw_coords(pin_node, iside, ioff, &x1, &y1);
x1 += draw_pin_off;
x2 = tile_x[chan_xlow] + tile_width + 1 + itrack;
y2 = y1;
if (is_opin(pin_num, type)) {
if (direction == INC_DIRECTION) {
y2 = tile_y[rr_node[chan_node].ylow];
} else if (direction == DEC_DIRECTION) {
y2 = tile_y[rr_node[chan_node].yhigh] + tile_width;
}
}
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "in draw_pin_to_chan_edge: Invalid channel node %d.\n", chan_node);
exit(1);
}
drawline(x1, y1, x2, y2);
if (direction == BI_DIRECTION || !is_opin(pin_num, type)) {
draw_x(x2, y2, 0.7 * pin_size);
} else {
xend = x2 + (x1 - x2) / 10.;
yend = y2 + (y1 - y2) / 10.;
draw_triangle_along_line(xend, yend, x1, x2, y1, y2);
}
}
static void draw_pin_to_pin(int opin_node, int ipin_node) {
/* This routine draws an edge from the opin rr node to the ipin rr node */
2019-05-13 15:45:02 -05:00
int opin_grid_x, opin_grid_y, opin;
int ipin_grid_x, ipin_grid_y, ipin;
2018-07-26 12:28:21 -05:00
int ofs, pin_ofs;
boolean found;
float x1, x2, y1, y2;
float xend, yend;
enum e_side iside, pin_side;
t_type_ptr type;
assert(rr_node[opin_node].type == OPIN);
assert(rr_node[ipin_node].type == IPIN);
iside = (enum e_side)0;
x1 = y1 = x2 = y2 = 0;
pin_ofs = 0;
pin_side = TOP;
/* get opin coordinate */
opin_grid_x = rr_node[opin_node].xlow;
opin_grid_y = rr_node[opin_node].ylow;
opin_grid_y = opin_grid_y - grid[opin_grid_x][opin_grid_y].offset;
opin = rr_node[opin_node].ptc_num;
type = grid[opin_grid_x][opin_grid_y].type;
found = FALSE;
for (ofs = 0; ofs < type->height && !found; ++ofs) {
for (iside = (enum e_side)0; iside < 4 && !found; iside = (enum e_side)(iside + 1)) {
/* Find first location of pin */
if (1 == type->pinloc[ofs][iside][opin]) {
pin_ofs = ofs;
pin_side = iside;
found = TRUE;
}
}
}
assert(found);
get_rr_pin_draw_coords(opin_node, pin_side, pin_ofs, &x1, &y1);
/* get ipin coordinate */
ipin_grid_x = rr_node[ipin_node].xlow;
ipin_grid_y = rr_node[ipin_node].ylow;
ipin_grid_y = ipin_grid_y - grid[ipin_grid_x][ipin_grid_y].offset;
ipin = rr_node[ipin_node].ptc_num;
type = grid[ipin_grid_x][ipin_grid_y].type;
found = FALSE;
for (ofs = 0; ofs < type->height && !found; ++ofs) {
for (iside = (enum e_side)0; iside < 4 && !found; iside = (enum e_side)(iside + 1)) {
/* Find first location of pin */
if (1 == type->pinloc[ofs][iside][ipin]) {
pin_ofs = ofs;
pin_side = iside;
found = TRUE;
}
}
}
assert(found);
get_rr_pin_draw_coords(ipin_node, pin_side, pin_ofs, &x2, &y2);
drawline(x1, y1, x2, y2);
xend = x2 + (x1 - x2) / 10.;
yend = y2 + (y1 - y2) / 10.;
draw_triangle_along_line(xend, yend, x1, x2, y1, y2);
}
/* UDSD by AY End */