VPR-6.0
|
00001 #include <stdio.h> 00002 #include <string.h> 00003 #include <math.h> 00004 #include "util.h" 00005 #include "vpr_types.h" 00006 #include "vpr_utils.h" 00007 #include "globals.h" 00008 #include "graphics.h" 00009 #include "path_delay.h" 00010 #include "draw.h" 00011 #include <assert.h> 00012 #include "read_xml_arch_file.h" 00013 00014 #ifdef DEBUG 00015 #include "rr_graph.h" 00016 #endif 00017 00018 /*************** Types local to this module *********************************/ 00019 #define MAX_BLOCK_COLOURS 5 00020 00021 enum e_draw_rr_toggle 00022 { 00023 DRAW_NO_RR = 0, 00024 DRAW_ALL_RR, 00025 DRAW_ALL_BUT_BUFFERS_RR, 00026 DRAW_NODES_AND_SBOX_RR, 00027 DRAW_NODES_RR, 00028 DRAW_RR_TOGGLE_MAX 00029 }; 00030 00031 enum e_draw_net_type 00032 { ALL_NETS, HIGHLIGHTED }; 00033 00034 enum e_edge_dir 00035 { FROM_X_TO_Y, FROM_Y_TO_X }; /* Chanx to chany or vice versa? */ 00036 00037 00038 /****************** Variables local to this module. *************************/ 00039 00040 /** Show nets of placement or routing? */ 00041 static boolean show_nets = FALSE; 00042 00043 /* Controls drawing of routing resources on screen, if pic_on_screen is * 00044 * ROUTING. */ 00045 00046 /** Can toggle to DRAW_NO_RR;*/ 00047 static enum e_draw_rr_toggle draw_rr_toggle = DRAW_NO_RR; /* UDSD by AY */ 00048 00049 static enum e_route_type draw_route_type; 00050 00051 /** Controls if congestion is shown, when ROUTING is on screen. */ 00052 static boolean show_congestion = FALSE; 00053 00054 /** Show defective stuff */ 00055 static boolean show_defects = FALSE; 00056 00057 /** Graphics enabled or not? */ 00058 static boolean show_graphics; 00059 00060 /** Default screen message on screen */ 00061 static char default_message[BUFSIZE]; 00062 00063 /** Need user input after: 0: each t, 00064 * 1: each place, 2: never 00065 */ 00066 static int gr_automode; 00067 00068 /** What do I draw? */ 00069 static enum pic_type pic_on_screen = NO_PICTURE; 00070 00071 /** The left and bottom coordinates of each grid_tile in the FPGA. 00072 * tile_x[0..nx+1] and tile_y[0..ny+1]. 00073 * COORDINATE SYSTEM goes from (0,0) at the lower left corner to 00074 * (tile_x[nx+1]+tile_width, tile_y[ny+1]+tile_width) in the 00075 * upper right corner. 00076 */ 00077 static float *tile_x, *tile_y; 00078 00079 /** Drawn width (and height) of a grid_tile, and the half-width or half-height of 00080 * a pin, respectively. Set when init_draw_coords is called. 00081 */ 00082 static float tile_width, pin_size; 00083 00084 /** Color in which each block and net should be drawn. 00085 * [0..num_nets-1] and [0..num_blocks-1], respectively. 00086 */ 00087 static enum color_types *net_color, *block_color; 00088 00089 static float line_fuz = 0.3; 00090 static char *name_type[] = { "SOURCE", "SINK", "IPIN", "OPIN", "CHANX", 00091 "CHANY", "INTRA_CLUSTER_EDGE" }; 00092 00093 static float *x_rr_node_left = NULL; 00094 static float *x_rr_node_right = NULL; 00095 static float *y_rr_node_top = NULL; 00096 static float *y_rr_node_bottom = NULL; 00097 static enum color_types *rr_node_color = NULL; 00098 static int old_num_rr_nodes = 0; 00099 00100 /********************** Subroutines local to this module ********************/ 00101 00102 static void toggle_nets(void (*drawscreen) (void)); 00103 static void toggle_rr(void (*drawscreen) (void)); 00104 static void toggle_defects(void (*drawscreen) (void)); 00105 static void toggle_congestion(void (*drawscreen) (void)); 00106 static void highlight_crit_path(void (*drawscreen_ptr) (void)); 00107 00108 static void drawscreen(void); 00109 static void redraw_screen(void); 00110 static void drawplace(void); 00111 static void drawnets(void); 00112 static void drawroute(enum e_draw_net_type draw_net_type); 00113 static void draw_congestion(void); 00114 00115 static void highlight_blocks(float x, 00116 float y); 00117 static void get_block_center(int bnum, 00118 float *x, 00119 float *y); 00120 static void deselect_all(void); 00121 00122 static void draw_rr(void); 00123 static void draw_rr_edges(int from_node); 00124 static void draw_rr_pin(int inode, 00125 enum color_types color); 00126 static void draw_rr_chanx(int inode, 00127 int itrack); 00128 static void draw_rr_chany(int inode, 00129 int itrack); 00130 static void get_rr_pin_draw_coords(int inode, 00131 int iside, 00132 int ioff, 00133 float *xcen, 00134 float *ycen); 00135 static void draw_pin_to_chan_edge(int pin_node, 00136 int chan_node); 00137 static void draw_x(float x, 00138 float y, 00139 float size); 00140 static void draw_chany_to_chany_edge(int from_node, 00141 int from_track, 00142 int to_node, 00143 int to_track, 00144 short switch_type); 00145 static void draw_chanx_to_chanx_edge(int from_node, 00146 int from_track, 00147 int to_node, 00148 int to_track, 00149 short switch_type); 00150 static void draw_chanx_to_chany_edge(int chanx_node, 00151 int chanx_track, 00152 int chany_node, 00153 int chany_track, 00154 enum e_edge_dir edge_dir, 00155 short switch_type); 00156 static int get_track_num(int inode, 00157 int **chanx_track, 00158 int **chany_track); 00159 static void draw_rr_switch(float from_x, 00160 float from_y, 00161 float to_x, 00162 float to_y, 00163 boolean buffered); 00164 static void draw_triangle_along_line(float xend, 00165 float yend, /* UDSD by AY */ 00166 00167 float x1, 00168 float x2, /* UDSD by AY */ 00169 00170 float y1, 00171 float y2); /* UDSD by AY */ 00172 00173 00174 /********************** Subroutine definitions ******************************/ 00175 00176 00177 /** Sets the static show_graphics and gr_automode variables to the 00178 * desired values. They control if graphics are enabled and, if so, 00179 * how often the user is prompted for input. 00180 */ 00181 void 00182 set_graphics_state(boolean show_graphics_val, 00183 int gr_automode_val, 00184 enum e_route_type route_type) 00185 { 00186 show_graphics = show_graphics_val; 00187 gr_automode = gr_automode_val; 00188 draw_route_type = route_type; 00189 } 00190 00191 00192 /** Updates the screen if the user has requested graphics. The priority 00193 * value controls whether or not the Proceed button must be clicked to 00194 * continue. Saves the pic_on_screen_val to allow pan and zoom redraws. 00195 */ 00196 void 00197 update_screen(int priority, 00198 char *msg, 00199 enum pic_type pic_on_screen_val, 00200 boolean crit_path_button_enabled) 00201 { 00202 if(!show_graphics) /* Graphics turned off */ 00203 return; 00204 00205 /* If it's the type of picture displayed has changed, set up the proper * 00206 * buttons. */ 00207 if(pic_on_screen != pic_on_screen_val) 00208 { 00209 if(pic_on_screen_val == PLACEMENT && pic_on_screen == NO_PICTURE) 00210 { 00211 create_button("Window", "Toggle Nets", toggle_nets); 00212 } 00213 else if(pic_on_screen_val == ROUTING 00214 && pic_on_screen == PLACEMENT) 00215 { 00216 create_button("Toggle Nets", "Toggle RR", toggle_rr); 00217 create_button("Toggle RR", "Tog Defects", toggle_defects); 00218 create_button("Toggle RR", "Congestion", 00219 toggle_congestion); 00220 00221 if(crit_path_button_enabled) 00222 { 00223 create_button("Congestion", "Crit. Path", 00224 highlight_crit_path); 00225 } 00226 } 00227 else if(pic_on_screen_val == PLACEMENT 00228 && pic_on_screen == ROUTING) 00229 { 00230 destroy_button("Toggle RR"); 00231 destroy_button("Congestion"); 00232 00233 if(crit_path_button_enabled) 00234 { 00235 destroy_button("Crit. Path"); 00236 } 00237 } 00238 else if(pic_on_screen_val == ROUTING 00239 && pic_on_screen == NO_PICTURE) 00240 { 00241 create_button("Window", "Toggle Nets", toggle_nets); 00242 create_button("Toggle Nets", "Toggle RR", toggle_rr); 00243 create_button("Toggle RR", "Tog Defects", toggle_defects); 00244 create_button("Tog Defects", "Congestion", 00245 toggle_congestion); 00246 00247 if(crit_path_button_enabled) 00248 { 00249 create_button("Congestion", "Crit. Path", 00250 highlight_crit_path); 00251 } 00252 } 00253 } 00254 /* Save the main message. */ 00255 00256 my_strncpy(default_message, msg, BUFSIZE); 00257 00258 pic_on_screen = pic_on_screen_val; 00259 update_message(msg); 00260 drawscreen(); 00261 if(priority >= gr_automode) 00262 { 00263 event_loop(highlight_blocks, drawscreen); 00264 } 00265 else 00266 { 00267 flushinput(); 00268 } 00269 } 00270 00271 00272 /** This is the screen redrawing routine that event_loop assumes exists. 00273 * It erases whatever is on screen, then calls redraw_screen to redraw 00274 * it. 00275 */ 00276 static void 00277 drawscreen() 00278 { 00279 00280 clearscreen(); 00281 redraw_screen(); 00282 } 00283 00284 00285 /** The screen redrawing routine called by drawscreen and 00286 * highlight_blocks. Call this routine instead of drawscreen if 00287 * you know you don't need to erase the current graphics, and want 00288 * to avoid a screen "flash". 00289 */ 00290 static void 00291 redraw_screen() 00292 { 00293 00294 setfontsize(14); /* UDSD Modification by WMF */ 00295 if(pic_on_screen == PLACEMENT) 00296 { 00297 drawplace(); 00298 if(show_nets) 00299 { 00300 drawnets(); 00301 } 00302 } 00303 else 00304 { /* ROUTING on screen */ 00305 drawplace(); 00306 00307 if(show_nets) 00308 { 00309 drawroute(ALL_NETS); 00310 } 00311 else 00312 { 00313 draw_rr(); 00314 } 00315 00316 if(show_congestion) 00317 { 00318 draw_congestion(); 00319 } 00320 } 00321 } 00322 00323 00324 /** Enables/disables drawing of nets when a the user clicks on a button. 00325 * Also disables drawing of routing resources. See graphics.c for details 00326 * of how buttons work. 00327 */ 00328 static void 00329 toggle_nets(void (*drawscreen_ptr) (void)) 00330 { 00331 show_nets = !show_nets; 00332 draw_rr_toggle = DRAW_NO_RR; 00333 show_congestion = FALSE; 00334 00335 update_message(default_message); 00336 drawscreen_ptr(); 00337 } 00338 00339 00340 /** Cycles through the options for viewing the routing resources available 00341 * in an FPGA. If a routing isn't on screen, the routing graph hasn't been 00342 * built, and this routine doesn't switch the view. Otherwise, this routine 00343 * switches to the routing resource view. Clicking on the toggle cycles 00344 * through the options: DRAW_NO_RR, DRAW_ALL_RR, DRAW_ALL_BUT_BUFFERS_RR, 00345 * DRAW_NODES_AND_SBOX_RR, and DRAW_NODES_RR. 00346 */ 00347 static void 00348 toggle_rr(void (*drawscreen_ptr) (void)) 00349 { 00350 draw_rr_toggle = (draw_rr_toggle + 1) % (DRAW_RR_TOGGLE_MAX); 00351 show_nets = FALSE; 00352 show_congestion = FALSE; 00353 00354 update_message(default_message); 00355 drawscreen_ptr(); 00356 } 00357 00358 static void 00359 toggle_defects(void (*drawscreen_ptr) (void)) 00360 { 00361 show_defects = !show_defects; 00362 update_message(default_message); 00363 drawscreen_ptr(); 00364 } 00365 00366 00367 /** Turns the congestion display on and off. */ 00368 static void 00369 toggle_congestion(void (*drawscreen_ptr) (void)) 00370 { 00371 char msg[BUFSIZE]; 00372 int inode, num_congested; 00373 00374 show_nets = FALSE; 00375 draw_rr_toggle = DRAW_NO_RR; 00376 show_congestion = !show_congestion; 00377 00378 if(!show_congestion) 00379 { 00380 update_message(default_message); 00381 } 00382 else 00383 { 00384 num_congested = 0; 00385 for(inode = 0; inode < num_rr_nodes; inode++) 00386 { 00387 if(rr_node[inode].occ > rr_node[inode].capacity) 00388 { 00389 num_congested++; 00390 } 00391 } 00392 00393 sprintf(msg, "%d routing resources are overused.", num_congested); 00394 update_message(msg); 00395 } 00396 00397 drawscreen_ptr(); 00398 } 00399 00400 00401 /** Highlights all the blocks and nets on the critical path. */ 00402 static void 00403 highlight_crit_path(void (*drawscreen_ptr) (void)) 00404 { 00405 t_linked_int *critical_path_head, *critical_path_node; 00406 int inode, iblk, inet, num_nets_seen; 00407 static int nets_to_highlight = 1; 00408 char msg[BUFSIZE]; 00409 00410 if(nets_to_highlight == 0) 00411 { /* Clear the display of all highlighting. */ 00412 nets_to_highlight = 1; 00413 deselect_all(); 00414 update_message(default_message); 00415 drawscreen_ptr(); 00416 return; 00417 } 00418 00419 critical_path_head = allocate_and_load_critical_path(); 00420 critical_path_node = critical_path_head; 00421 num_nets_seen = 0; 00422 00423 while(critical_path_node != NULL) 00424 { 00425 inode = critical_path_node->data; 00426 get_tnode_block_and_output_net(inode, &iblk, &inet); 00427 00428 if(num_nets_seen == nets_to_highlight) 00429 { /* Last block */ 00430 block_color[iblk] = MAGENTA; 00431 } 00432 else if(num_nets_seen == nets_to_highlight - 1) 00433 { /* 2nd last block */ 00434 block_color[iblk] = YELLOW; 00435 } 00436 else if(num_nets_seen < nets_to_highlight) 00437 { /* Earlier block */ 00438 block_color[iblk] = DARKGREEN; 00439 } 00440 00441 if(inet != OPEN) 00442 { 00443 num_nets_seen++; 00444 00445 if(num_nets_seen < nets_to_highlight) 00446 { /* First nets. */ 00447 net_color[inet] = DARKGREEN; 00448 } 00449 else if(num_nets_seen == nets_to_highlight) 00450 { 00451 net_color[inet] = CYAN; /* Last (new) net. */ 00452 } 00453 } 00454 00455 critical_path_node = critical_path_node->next; 00456 } 00457 00458 if(nets_to_highlight == num_nets_seen) 00459 { 00460 nets_to_highlight = 0; 00461 sprintf(msg, "All %d nets on the critical path highlighted.", 00462 num_nets_seen); 00463 } 00464 else 00465 { 00466 sprintf(msg, "First %d nets on the critical path highlighted.", 00467 nets_to_highlight); 00468 nets_to_highlight++; 00469 } 00470 00471 free_int_list(&critical_path_head); 00472 00473 update_message(msg); 00474 drawscreen_ptr(); 00475 } 00476 00477 00478 /** Allocate the structures needed to draw the placement and routing. Set 00479 * up the default colors for blocks and nets. 00480 */ 00481 void 00482 alloc_draw_structs(void) 00483 { 00484 tile_x = (float *)my_malloc((nx + 2) * sizeof(float)); 00485 tile_y = (float *)my_malloc((ny + 2) * sizeof(float)); 00486 00487 net_color = (enum color_types *) 00488 my_malloc(num_nets * sizeof(enum color_types)); 00489 00490 block_color = (enum color_types *) 00491 my_malloc(num_blocks * sizeof(enum color_types)); 00492 00493 x_rr_node_left = (float *) my_malloc(num_rr_nodes*sizeof(float)); 00494 x_rr_node_right = (float *) my_malloc(num_rr_nodes*sizeof(float)); 00495 y_rr_node_top = (float *) my_malloc(num_rr_nodes*sizeof(float)); 00496 y_rr_node_bottom = (float *) my_malloc(num_rr_nodes*sizeof(float)); 00497 rr_node_color = (enum color_types *) my_malloc(num_rr_nodes*sizeof(enum color_types)); 00498 00499 deselect_all(); /* Set initial colors */ 00500 } 00501 00502 00503 /** Load the arrays containing the left and bottom coordinates of the clbs 00504 * forming the FPGA. tile_width_val sets the width and height of a drawn 00505 * clb. 00506 */ 00507 void 00508 init_draw_coords(float width_val) 00509 { 00510 int i; 00511 int j; 00512 00513 if(!show_graphics) 00514 return; /* -nodisp was selected. */ 00515 00516 if(num_rr_nodes != old_num_rr_nodes) 00517 { 00518 x_rr_node_left = (float *) my_realloc(x_rr_node_left, (num_rr_nodes)*sizeof(float)); 00519 x_rr_node_right = (float *) my_realloc(x_rr_node_right, (num_rr_nodes)*sizeof(float)); 00520 y_rr_node_top = (float *) my_realloc(y_rr_node_top, (num_rr_nodes)*sizeof(float)); 00521 y_rr_node_bottom = (float *) my_realloc(y_rr_node_bottom, (num_rr_nodes)*sizeof(float)); 00522 rr_node_color = (enum color_types *) my_realloc(rr_node_color, (num_rr_nodes)*sizeof(enum color_types)); 00523 for (i = 0; i < num_rr_nodes; i++) 00524 { 00525 x_rr_node_left[i] = -1; 00526 x_rr_node_right[i] = -1; 00527 y_rr_node_top[i] = -1; 00528 y_rr_node_bottom[i] = -1; 00529 rr_node_color[i] = BLACK; 00530 } 00531 } 00532 00533 00534 tile_width = width_val; 00535 pin_size = 0.3; 00536 for(i = 0; i < num_types; ++i) 00537 { 00538 pin_size = 00539 min(pin_size, 00540 (tile_width / (4.0 * type_descriptors[i].num_pins))); 00541 } 00542 00543 j = 0; 00544 for(i = 0; i < (nx + 1); i++) 00545 { 00546 tile_x[i] = (i * tile_width) + j; 00547 j += chan_width_y[i] + 1; /* N wires need N+1 units of space */ 00548 } 00549 tile_x[nx + 1] = ((nx + 1) * tile_width) + j; 00550 00551 j = 0; 00552 for(i = 0; i < (ny + 1); ++i) 00553 { 00554 tile_y[i] = (i * tile_width) + j; 00555 j += chan_width_x[i] + 1; 00556 } 00557 tile_y[ny + 1] = ((ny + 1) * tile_width) + j; 00558 00559 init_world(0.0, 00560 tile_y[ny + 1] + tile_width, tile_x[nx + 1] + tile_width, 0.0); 00561 } 00562 00563 00564 /** Draws the blocks placed on the proper clbs. Occupied blocks are darker colours 00565 * while empty ones are lighter colours and have a dashed border. 00566 */ 00567 static void 00568 drawplace(void) 00569 { 00570 float sub_tile_step; 00571 float x1, y1, x2, y2; 00572 int i, j, k, bnum; 00573 int num_sub_tiles; 00574 int height; 00575 00576 setlinewidth(0); 00577 00578 for(i = 0; i <= (nx + 1); i++) 00579 { 00580 for(j = 0; j <= (ny + 1); j++) 00581 { 00582 /* Only the first block of a group should control drawing */ 00583 if(grid[i][j].offset > 0) 00584 continue; 00585 00586 /* Don't draw corners */ 00587 if(((i < 1) || (i > nx)) && ((j < 1) || (j > ny))) 00588 continue; 00589 00590 num_sub_tiles = grid[i][j].type->capacity; 00591 sub_tile_step = tile_width / num_sub_tiles; 00592 height = grid[i][j].type->height; 00593 00594 if(num_sub_tiles < 1) 00595 { 00596 setcolor(BLACK); 00597 setlinestyle(DASHED); 00598 drawrect(tile_x[i], tile_y[j], 00599 tile_x[i] + tile_width, 00600 tile_y[j] + tile_width); 00601 draw_x(tile_x[i] + (tile_width / 2), 00602 tile_y[j] + (tile_width / 2), 00603 (tile_width / 2)); 00604 } 00605 00606 for(k = 0; k < num_sub_tiles; ++k) 00607 { 00608 /* Graphics will look unusual for multiple height and capacity */ 00609 assert(height == 1 || num_sub_tiles == 1); 00610 /* Get coords of current sub_tile */ 00611 if((i < 1) || (i > nx)) 00612 { /* left and right fringes */ 00613 x1 = tile_x[i]; 00614 y1 = tile_y[j] + (k * sub_tile_step); 00615 x2 = x1 + tile_width; 00616 y2 = y1 + sub_tile_step; 00617 } 00618 else if((j < 1) || (j > ny)) 00619 { /* top and bottom fringes */ 00620 x1 = tile_x[i] + (k * sub_tile_step); 00621 y1 = tile_y[j]; 00622 x2 = x1 + sub_tile_step; 00623 y2 = y1 + tile_width; 00624 } 00625 else 00626 { 00627 assert(num_sub_tiles <= 1); /* Need to change draw code to support */ 00628 00629 x1 = tile_x[i]; 00630 y1 = tile_y[j]; 00631 x2 = x1 + tile_width; 00632 y2 = tile_y[j + height - 1] + tile_width; 00633 } 00634 00635 /* Look at the tile at start of large block */ 00636 bnum = grid[i][j].blocks[k]; 00637 00638 00639 /* Draw background */ 00640 if(bnum != EMPTY) 00641 { 00642 setcolor(block_color[bnum]); 00643 fillrect(x1, y1, x2, y2); 00644 } else { 00645 /* colour empty blocks a particular colour depending on type */ 00646 if(grid[i][j].type->index < 3) { 00647 setcolor(WHITE); 00648 } else if(grid[i][j].type->index < 3 + MAX_BLOCK_COLOURS) { 00649 setcolor(BISQUE + grid[i][j].type->index - 3); 00650 } else { 00651 setcolor(BISQUE + MAX_BLOCK_COLOURS - 1); 00652 } 00653 fillrect(x1, y1, x2, y2); 00654 } 00655 00656 setcolor(BLACK); 00657 00658 setlinestyle((EMPTY == bnum) ? DASHED : SOLID); 00659 drawrect(x1, y1, x2, y2); 00660 00661 /* Draw text if the space has parts of the netlist */ 00662 if(bnum != EMPTY) 00663 { 00664 drawtext((x1 + x2) / 2.0, (y1 + y2) / 2.0, 00665 block[bnum].name, tile_width); 00666 } 00667 00668 /* Draw text for block type so that user knows what block */ 00669 if(grid[i][j].offset == 0) { 00670 if(i > 0 && i <= nx && j > 0 && j <= ny) { 00671 drawtext((x1 + x2) / 2.0, y1 + (tile_width / 4.0), 00672 grid[i][j].type->name, tile_width); 00673 } 00674 } 00675 } 00676 } 00677 } 00678 } 00679 00680 00681 /** This routine draws the nets on the placement. The nets have not 00682 * yet been routed, so we just draw a chain showing a possible path 00683 * for each net. This gives some idea of future congestion. 00684 */ 00685 static void 00686 drawnets(void) 00687 { 00688 int inet, ipin, b1, b2; 00689 float x1, y1, x2, y2; 00690 00691 setlinestyle(SOLID); 00692 setlinewidth(0); 00693 00694 /* Draw the net as a star from the source to each sink. Draw from centers of * 00695 * blocks (or sub blocks in the case of IOs). */ 00696 00697 for(inet = 0; inet < num_nets; inet++) 00698 { 00699 if(clb_net[inet].is_global) 00700 continue; /* Don't draw global nets. */ 00701 00702 setcolor(net_color[inet]); 00703 b1 = clb_net[inet].node_block[0]; /* The DRIVER */ 00704 get_block_center(b1, &x1, &y1); 00705 00706 for(ipin = 1; ipin < (clb_net[inet].num_sinks + 1); ipin++) 00707 { 00708 b2 = clb_net[inet].node_block[ipin]; 00709 get_block_center(b2, &x2, &y2); 00710 drawline(x1, y1, x2, y2); 00711 00712 /* Uncomment to draw a chain instead of a star. */ 00713 /* x1 = x2; */ 00714 /* y1 = y2; */ 00715 } 00716 } 00717 } 00718 00719 00720 /** This routine finds the center of block bnum in the current placement, 00721 * and returns it in *x and *y. This is used in routine shownets. 00722 */ 00723 static void 00724 get_block_center(int bnum, 00725 float *x, 00726 float *y) 00727 { 00728 00729 int i, j, k; 00730 float sub_tile_step; 00731 00732 i = block[bnum].x; 00733 j = block[bnum].y; 00734 k = block[bnum].z; 00735 00736 sub_tile_step = tile_width / block[bnum].type->capacity; 00737 00738 if((i < 1) || (i > nx)) 00739 { /* Left and right fringe */ 00740 *x = tile_x[i] + (sub_tile_step * (k + 0.5)); 00741 } 00742 else 00743 { 00744 *x = tile_x[i] + (tile_width / 2.0); 00745 } 00746 00747 if((j < 1) || (j > ny)) 00748 { /* Top and bottom fringe */ 00749 *y = tile_y[j] + (sub_tile_step * (k + 0.5)); 00750 } 00751 else 00752 { 00753 *y = tile_y[j] + (tile_width / 2.0); 00754 } 00755 } 00756 00757 /** Draws all the overused routing resources (i.e. congestion) in RED. */ 00758 static void 00759 draw_congestion(void) 00760 { 00761 int inode, itrack; 00762 00763 setcolor(RED); 00764 setlinewidth(2); 00765 00766 for(inode = 0; inode < num_rr_nodes; inode++) 00767 { 00768 if(rr_node[inode].occ > rr_node[inode].capacity) 00769 { 00770 switch (rr_node[inode].type) 00771 { 00772 case CHANX: 00773 itrack = rr_node[inode].ptc_num; 00774 draw_rr_chanx(inode, itrack); 00775 break; 00776 00777 case CHANY: 00778 itrack = rr_node[inode].ptc_num; 00779 draw_rr_chany(inode, itrack); 00780 break; 00781 00782 case IPIN: 00783 case OPIN: 00784 draw_rr_pin(inode, RED); 00785 break; 00786 default: 00787 break; 00788 } 00789 } 00790 } 00791 } 00792 00793 00794 /** Draws the routing resources that exist in the FPGA, if the user wants 00795 * them drawn. 00796 */ 00797 void 00798 draw_rr(void) 00799 { 00800 int inode, itrack; 00801 00802 if(draw_rr_toggle == DRAW_NO_RR) 00803 { 00804 setlinewidth(3); 00805 drawroute(HIGHLIGHTED); 00806 setlinewidth(0); 00807 return; 00808 } 00809 00810 setlinestyle(SOLID); 00811 setlinewidth(0); 00812 00813 for(inode = 0; inode < num_rr_nodes; inode++) 00814 { 00815 switch (rr_node[inode].type) 00816 { 00817 00818 case SOURCE: 00819 case SINK: 00820 break; /* Don't draw. */ 00821 00822 case CHANX: 00823 if(show_defects && (rr_node[inode].capacity <= 0)) 00824 setcolor(RED); 00825 else 00826 setcolor(BLACK); 00827 if(show_defects && (rr_node[inode].occ > 0)) 00828 setcolor(CYAN); 00829 itrack = rr_node[inode].ptc_num; 00830 draw_rr_chanx(inode, itrack); 00831 draw_rr_edges(inode); 00832 break; 00833 00834 case CHANY: 00835 if(show_defects && (rr_node[inode].capacity <= 0)) 00836 setcolor(RED); 00837 else 00838 setcolor (BLACK); 00839 if(show_defects && (rr_node[inode].occ > 0)) 00840 setcolor(CYAN); 00841 itrack = rr_node[inode].ptc_num; 00842 draw_rr_chany(inode, itrack); 00843 draw_rr_edges(inode); 00844 break; 00845 00846 case IPIN: 00847 if(show_defects) 00848 { 00849 if(rr_node[inode].capacity < 0) 00850 draw_rr_pin(inode, RED); 00851 else if(rr_node[inode].occ > 0) 00852 draw_rr_pin(inode, CYAN); 00853 else 00854 draw_rr_pin(inode, BLACK); 00855 } 00856 else 00857 draw_rr_pin(inode, BLUE); 00858 break; 00859 00860 case OPIN: 00861 if(show_defects) 00862 { 00863 if(rr_node[inode].capacity < 0) 00864 draw_rr_pin(inode, RED); 00865 else if(rr_node[inode].occ > 0) 00866 draw_rr_pin(inode, CYAN); 00867 else 00868 draw_rr_pin(inode, BLACK); 00869 setcolor(BLACK); 00870 } 00871 else 00872 { 00873 draw_rr_pin(inode, RED); 00874 setcolor(RED); 00875 } 00876 setcolor(RED); 00877 draw_rr_edges(inode); 00878 break; 00879 00880 default: 00881 printf 00882 ("Error in draw_rr: Unexpected rr_node type: %d.\n", 00883 rr_node[inode].type); 00884 exit(1); 00885 } 00886 } 00887 00888 setlinewidth(3); 00889 drawroute(HIGHLIGHTED); 00890 setlinewidth(0); 00891 } 00892 00893 00894 /** Draws an x-directed channel segment. */ 00895 static void 00896 draw_rr_chanx(int inode, 00897 int itrack) 00898 { 00899 enum 00900 { BUFFSIZE = 80 }; 00901 float x1, x2, y; 00902 float y1, y2; /* UDSD by AY */ 00903 int k; /* UDSD by AY */ 00904 char str[BUFFSIZE]; 00905 int savecolor; 00906 00907 /* Track 0 at bottom edge, closest to "owning" clb. */ 00908 00909 x1 = tile_x[rr_node[inode].xlow]; 00910 x2 = tile_x[rr_node[inode].xhigh] + tile_width; 00911 y = tile_y[rr_node[inode].ylow] + tile_width + 1.0 + itrack; 00912 x_rr_node_left[inode] = x1; 00913 x_rr_node_right[inode] = x2; 00914 y_rr_node_bottom[inode] = y - line_fuz; 00915 y_rr_node_top[inode] = y + line_fuz; 00916 if(rr_node_color[inode] != BLACK) 00917 { 00918 savecolor=getcolor(); 00919 setcolor(rr_node_color[inode]); 00920 setlinewidth(3); 00921 drawline(x1, y, x2, y); 00922 setlinewidth(0); 00923 setcolor(savecolor); 00924 } 00925 else 00926 { 00927 drawline(x1, y, x2, y); 00928 } 00929 /* UDSD by AY Start */ 00930 y1 = y - 0.25; 00931 y2 = y + 0.25; 00932 00933 if(rr_node[inode].direction == INC_DIRECTION) 00934 { 00935 setlinewidth(2); 00936 setcolor(YELLOW); 00937 drawline(x1, y1, x1, y2); /* Draw a line at start of wire to indicate mux */ 00938 00939 /* Mux balence numbers */ 00940 setcolor(BLACK); 00941 sprintf(str, "%d", rr_node[inode].fan_in); 00942 drawtext(x1, y, str, 5); 00943 00944 setcolor(BLACK); 00945 setlinewidth(0); 00946 draw_triangle_along_line(x2 - 0.15, y, x1, x2, y, y); 00947 00948 setcolor(LIGHTGREY); 00949 /* TODO: this looks odd, why does it ignore final block? does this mean nothing appears with L=1 ? */ 00950 for(k = rr_node[inode].xlow; k < rr_node[inode].xhigh; k++) 00951 { 00952 x2 = tile_x[k] + tile_width; 00953 draw_triangle_along_line(x2 - 0.15, y, x1, x2, y, y); 00954 x2 = tile_x[k + 1]; 00955 draw_triangle_along_line(x2 + 0.15, y, x1, x2, y, y); 00956 } 00957 setcolor(BLACK); 00958 } 00959 else if(rr_node[inode].direction == DEC_DIRECTION) 00960 { 00961 setlinewidth(2); 00962 setcolor(YELLOW); 00963 drawline(x2, y1, x2, y2); 00964 00965 /* Mux balance numbers */ 00966 setcolor(BLACK); 00967 sprintf(str, "%d", rr_node[inode].fan_in); 00968 drawtext(x2, y, str, 5); 00969 00970 setlinewidth(0); 00971 draw_triangle_along_line(x1 + 0.15, y, x2, x1, y, y); 00972 setcolor(LIGHTGREY); 00973 for(k = rr_node[inode].xhigh; k > rr_node[inode].xlow; k--) 00974 { 00975 x1 = tile_x[k]; 00976 draw_triangle_along_line(x1 + 0.15, y, x2, x1, y, y); 00977 x1 = tile_x[k - 1] + tile_width; 00978 draw_triangle_along_line(x1 - 0.15, y, x2, x1, y, y); 00979 } 00980 setcolor(BLACK); 00981 } 00982 /* UDSD by AY End */ 00983 } 00984 00985 00986 /** Draws a y-directed channel segment. */ 00987 static void 00988 draw_rr_chany(int inode, 00989 int itrack) 00990 { 00991 enum 00992 { BUFFSIZE = 80 }; 00993 float x, y1, y2; 00994 float x1, x2; /* UDSD by AY */ 00995 int k; /* UDSD by AY */ 00996 char str[BUFFSIZE]; 00997 int savecolor; 00998 00999 /* Track 0 at left edge, closest to "owning" clb. */ 01000 01001 x = tile_x[rr_node[inode].xlow] + tile_width + 1. + itrack; 01002 y1 = tile_y[rr_node[inode].ylow]; 01003 y2 = tile_y[rr_node[inode].yhigh] + tile_width; 01004 x_rr_node_left[inode] = x - line_fuz; 01005 x_rr_node_right[inode] = x + line_fuz; 01006 y_rr_node_bottom[inode] = y1; 01007 y_rr_node_top[inode] = y2; 01008 if(rr_node_color[inode] != BLACK) 01009 { 01010 savecolor=getcolor(); 01011 setcolor(rr_node_color[inode]); 01012 setlinewidth(3); 01013 drawline(x, y1, x, y2); 01014 setlinewidth(0); 01015 setcolor(savecolor); 01016 } 01017 else 01018 { 01019 drawline(x, y1, x, y2); 01020 } 01021 01022 /* UDSD by AY Start */ 01023 x1 = x - 0.25; 01024 x2 = x + 0.25; 01025 if(rr_node[inode].direction == INC_DIRECTION) 01026 { 01027 setlinewidth(2); 01028 setcolor(YELLOW); 01029 drawline(x1, y1, x2, y1); 01030 01031 /* UDSD Modifications by WMF Begin */ 01032 setcolor(BLACK); 01033 sprintf(str, "%d", rr_node[inode].fan_in); 01034 drawtext(x, y1, str, 5); 01035 setcolor(BLACK); 01036 /* UDSD Modifications by WMF End */ 01037 01038 setlinewidth(0); 01039 draw_triangle_along_line(x, y2 - 0.15, x, x, y1, y2); 01040 setcolor(LIGHTGREY); 01041 for(k = rr_node[inode].ylow; k < rr_node[inode].yhigh; k++) 01042 { 01043 y2 = tile_y[k] + tile_width; 01044 draw_triangle_along_line(x, y2 - 0.15, x, x, y1, y2); 01045 y2 = tile_y[k + 1]; 01046 draw_triangle_along_line(x, y2 + 0.15, x, x, y1, y2); 01047 } 01048 setcolor(BLACK); 01049 } 01050 else if(rr_node[inode].direction == DEC_DIRECTION) 01051 { 01052 setlinewidth(2); 01053 setcolor(YELLOW); 01054 drawline(x1, y2, x2, y2); 01055 01056 /* UDSD Modifications by WMF Begin */ 01057 setcolor(BLACK); 01058 sprintf(str, "%d", rr_node[inode].fan_in); 01059 drawtext(x, y2, str, 5); 01060 setcolor(BLACK); 01061 /* UDSD Modifications by WMF End */ 01062 01063 setlinewidth(0); 01064 draw_triangle_along_line(x, y1 + 0.15, x, x, y2, y1); 01065 setcolor(LIGHTGREY); 01066 for(k = rr_node[inode].yhigh; k > rr_node[inode].ylow; k--) 01067 { 01068 y1 = tile_y[k]; 01069 draw_triangle_along_line(x, y1 + 0.15, x, x, y2, y1); 01070 y1 = tile_y[k - 1] + tile_width; 01071 draw_triangle_along_line(x, y1 - 0.15, x, x, y2, y1); 01072 } 01073 setcolor(BLACK); 01074 } 01075 /* UDSD by AY End */ 01076 } 01077 01078 01079 /** Draws all the edges that the user wants shown between inode and what it 01080 * connects to. inode is assumed to be a CHANX, CHANY, or OPIN. 01081 */ 01082 static void 01083 draw_rr_edges(int inode) 01084 { 01085 01086 t_rr_type from_type, to_type; 01087 int iedge, to_node, from_ptc_num, to_ptc_num; 01088 short switch_type; 01089 boolean defective=FALSE; 01090 01091 from_type = rr_node[inode].type; 01092 01093 if((draw_rr_toggle == DRAW_NODES_RR) || 01094 (draw_rr_toggle == DRAW_NODES_AND_SBOX_RR && from_type == OPIN)) 01095 { 01096 return; /* Nothing to draw. */ 01097 } 01098 01099 from_ptc_num = rr_node[inode].ptc_num; 01100 01101 for(iedge = 0; iedge < rr_node[inode].num_edges; iedge++) 01102 { 01103 to_node = rr_node[inode].edges[iedge]; 01104 to_type = rr_node[to_node].type; 01105 to_ptc_num = rr_node[to_node].ptc_num; 01106 01107 if(show_defects) 01108 defective = (switch_inf[rr_node[inode].switches[iedge]].R < 0); 01109 switch (from_type) 01110 { 01111 01112 case OPIN: 01113 switch (to_type) 01114 { 01115 case CHANX: 01116 case CHANY: 01117 if(show_defects) 01118 { 01119 if(defective) 01120 setcolor(RED); 01121 else 01122 setcolor(BLACK); 01123 } 01124 else 01125 setcolor(RED); 01126 draw_pin_to_chan_edge(inode, to_node); 01127 break; 01128 01129 default: 01130 printf 01131 ("Error in draw_rr_edges: node %d (type: %d) connects to \n" 01132 "node %d (type: %d).\n", inode, from_type, 01133 to_node, to_type); 01134 exit(1); 01135 break; 01136 } 01137 break; 01138 01139 case CHANX: /* from_type */ 01140 switch (to_type) 01141 { 01142 case IPIN: 01143 if(draw_rr_toggle == DRAW_NODES_AND_SBOX_RR) 01144 { 01145 break; 01146 } 01147 01148 if(show_defects) 01149 { 01150 if(defective) 01151 setcolor(RED); 01152 else 01153 setcolor(BLACK); 01154 } 01155 else 01156 setcolor(BLUE); 01157 draw_pin_to_chan_edge(to_node, inode); 01158 break; 01159 01160 case CHANX: 01161 if(show_defects) 01162 { 01163 if(defective) 01164 setcolor(RED); 01165 else 01166 setcolor(BLACK); 01167 } 01168 else 01169 setcolor(DARKGREEN); 01170 switch_type = rr_node[inode].switches[iedge]; 01171 draw_chanx_to_chanx_edge(inode, from_ptc_num, 01172 to_node, to_ptc_num, 01173 switch_type); 01174 break; 01175 01176 case CHANY: 01177 if(show_defects) 01178 { 01179 if(defective) 01180 setcolor(RED); 01181 else 01182 setcolor(BLACK); 01183 } 01184 else 01185 setcolor(DARKGREEN); 01186 switch_type = rr_node[inode].switches[iedge]; 01187 draw_chanx_to_chany_edge(inode, from_ptc_num, 01188 to_node, to_ptc_num, 01189 FROM_X_TO_Y, 01190 switch_type); 01191 break; 01192 01193 default: 01194 printf 01195 ("Error in draw_rr_edges: node %d (type: %d) connects to \n" 01196 "node %d (type: %d).\n", inode, from_type, 01197 to_node, to_type); 01198 exit(1); 01199 break; 01200 } 01201 break; 01202 01203 01204 case CHANY: /* from_type */ 01205 switch (to_type) 01206 { 01207 case IPIN: 01208 if(draw_rr_toggle == DRAW_NODES_AND_SBOX_RR) 01209 { 01210 break; 01211 } 01212 01213 if(show_defects) 01214 { 01215 if(defective) 01216 setcolor(RED); 01217 else 01218 setcolor(BLACK); 01219 } 01220 else 01221 setcolor(BLUE); 01222 draw_pin_to_chan_edge(to_node, inode); 01223 break; 01224 01225 case CHANX: 01226 if(show_defects) 01227 { 01228 if(defective) 01229 setcolor(RED); 01230 else 01231 setcolor(BLACK); 01232 } 01233 else 01234 setcolor(DARKGREEN); 01235 switch_type = rr_node[inode].switches[iedge]; 01236 draw_chanx_to_chany_edge(to_node, to_ptc_num, 01237 inode, from_ptc_num, 01238 FROM_Y_TO_X, 01239 switch_type); 01240 break; 01241 01242 case CHANY: 01243 if(show_defects) 01244 { 01245 if(defective) 01246 setcolor(RED); 01247 else 01248 setcolor(BLACK); 01249 } 01250 else 01251 setcolor(DARKGREEN); 01252 switch_type = rr_node[inode].switches[iedge]; 01253 draw_chany_to_chany_edge(inode, from_ptc_num, 01254 to_node, to_ptc_num, 01255 switch_type); 01256 break; 01257 01258 default: 01259 printf 01260 ("Error in draw_rr_edges: node %d (type: %d) connects to \n" 01261 "node %d (type: %d).\n", inode, from_type, 01262 to_node, to_type); 01263 exit(1); 01264 break; 01265 } 01266 break; 01267 01268 default: /* from_type */ 01269 printf 01270 ("Error: draw_rr_edges called with node %d of type %d.\n", 01271 inode, from_type); 01272 exit(1); 01273 break; 01274 } 01275 } /* End of for each edge loop */ 01276 } 01277 01278 /** Draws an X centered at (x,y). The width and height of the X are each 01279 * 2 * size. 01280 */ 01281 static void 01282 draw_x(float x, 01283 float y, 01284 float size) 01285 { 01286 01287 drawline(x - size, y + size, x + size, y - size); 01288 drawline(x - size, y - size, x + size, y + size); 01289 } 01290 01291 01292 /** Draws an edge (SBOX connection) between an x-directed channel and a 01293 * y-directed channel. 01294 */ 01295 /* UDSD Modifications by WMF: Thank God Andy fixed this. */ 01296 static void 01297 draw_chanx_to_chany_edge(int chanx_node, 01298 int chanx_track, 01299 int chany_node, 01300 int chany_track, 01301 enum e_edge_dir edge_dir, 01302 short switch_type) 01303 { 01304 float x1, y1, x2, y2; 01305 int chanx_y, chany_x, chanx_xlow, chany_ylow; 01306 01307 chanx_y = rr_node[chanx_node].ylow; 01308 chanx_xlow = rr_node[chanx_node].xlow; 01309 chany_x = rr_node[chany_node].xlow; 01310 chany_ylow = rr_node[chany_node].ylow; 01311 01312 /* (x1,y1): point on CHANX segment, (x2,y2): point on CHANY segment. */ 01313 01314 y1 = tile_y[chanx_y] + tile_width + 1. + chanx_track; 01315 x2 = tile_x[chany_x] + tile_width + 1. + chany_track; 01316 01317 if(chanx_xlow <= chany_x) 01318 { /* Can draw connection going right */ 01319 x1 = tile_x[chany_x] + tile_width; 01320 /* UDSD by AY Start */ 01321 if(rr_node[chanx_node].direction != BI_DIRECTION) 01322 { 01323 if(edge_dir == FROM_X_TO_Y) 01324 { 01325 if((chanx_track % 2) == 1) 01326 { /* UDSD Modifications by WMF: If dec wire, then going left */ 01327 x1 = tile_x[chany_x + 1]; 01328 } 01329 } 01330 } 01331 /* UDSD by AY End */ 01332 } 01333 else 01334 { /* Must draw connection going left. */ 01335 x1 = tile_x[chanx_xlow]; 01336 } 01337 01338 if(chany_ylow <= chanx_y) 01339 { /* Can draw connection going up. */ 01340 y2 = tile_y[chanx_y] + tile_width; 01341 /* UDSD by AY Start */ 01342 if(rr_node[chany_node].direction != BI_DIRECTION) 01343 { 01344 if(edge_dir == FROM_Y_TO_X) 01345 { 01346 if((chany_track % 2) == 1) 01347 { /* UDSD Modifications by WMF: If dec wire, then going down */ 01348 y2 = tile_y[chanx_y + 1]; 01349 } 01350 } 01351 } 01352 /* UDSD by AY End */ 01353 } 01354 else 01355 { /* Must draw connection going down. */ 01356 y2 = tile_y[chany_ylow]; 01357 } 01358 01359 drawline(x1, y1, x2, y2); 01360 01361 if(draw_rr_toggle != DRAW_ALL_RR) 01362 return; 01363 01364 if(edge_dir == FROM_X_TO_Y) 01365 draw_rr_switch(x1, y1, x2, y2, switch_inf[switch_type].buffered); 01366 else 01367 draw_rr_switch(x2, y2, x1, y1, switch_inf[switch_type].buffered); 01368 } 01369 01370 01371 /** Draws a connection between two x-channel segments. Passing in the track 01372 * numbers allows this routine to be used for both rr_graph and routing 01373 * drawing. 01374 */ 01375 static void 01376 draw_chanx_to_chanx_edge(int from_node, 01377 int from_track, 01378 int to_node, 01379 int to_track, 01380 short switch_type) 01381 { 01382 float x1, x2, y1, y2; 01383 int from_y, to_y, from_xlow, to_xlow, from_xhigh, to_xhigh; 01384 01385 from_y = rr_node[from_node].ylow; 01386 from_xlow = rr_node[from_node].xlow; 01387 from_xhigh = rr_node[from_node].xhigh; 01388 to_y = rr_node[to_node].ylow; 01389 to_xlow = rr_node[to_node].xlow; 01390 to_xhigh = rr_node[to_node].xhigh; 01391 01392 /* (x1, y1) point on from_node, (x2, y2) point on to_node. */ 01393 01394 y1 = tile_y[from_y] + tile_width + 1 + from_track; 01395 y2 = tile_y[to_y] + tile_width + 1 + to_track; 01396 01397 01398 if(to_xhigh < from_xlow) 01399 { /* From right to left */ 01400 /* UDSD Note by WMF: could never happen for INC wires, unless U-turn. For DEC 01401 * wires this handles well */ 01402 x1 = tile_x[from_xlow]; 01403 x2 = tile_x[to_xhigh] + tile_width; 01404 } 01405 else if(to_xlow > from_xhigh) 01406 { /* From left to right */ 01407 /* UDSD Note by WMF: could never happen for DEC wires, unless U-turn. For INC 01408 * wires this handles well */ 01409 x1 = tile_x[from_xhigh] + tile_width; 01410 x2 = tile_x[to_xlow]; 01411 } 01412 01413 /* Segments overlap in the channel. Figure out best way to draw. Have to * 01414 * make sure the drawing is symmetric in the from rr and to rr so the edges * 01415 * will be drawn on top of each other for bidirectional connections. */ 01416 01417 /* UDSD Modification by WMF Begin */ 01418 else 01419 { 01420 if(rr_node[to_node].direction != BI_DIRECTION) 01421 { 01422 /* must connect to to_node's wire beginning at x2 */ 01423 if(to_track % 2 == 0) 01424 { /* INC wire starts at leftmost edge */ 01425 assert(from_xlow < to_xlow); 01426 x2 = tile_x[to_xlow]; 01427 /* since no U-turns from_track must be INC as well */ 01428 x1 = tile_x[to_xlow - 1] + tile_width; 01429 } 01430 else 01431 { /* DEC wire starts at rightmost edge */ 01432 assert(from_xhigh > to_xhigh); 01433 x2 = tile_x[to_xhigh] + tile_width; 01434 x1 = tile_x[to_xhigh + 1]; 01435 } 01436 } 01437 else 01438 { 01439 if(to_xlow < from_xlow) 01440 { /* Draw from left edge of one to other */ 01441 x1 = tile_x[from_xlow]; 01442 x2 = tile_x[from_xlow - 1] + tile_width; 01443 } 01444 else if(from_xlow < to_xlow) 01445 { 01446 x1 = tile_x[to_xlow - 1] + tile_width; 01447 x2 = tile_x[to_xlow]; 01448 } /* The following then is executed when from_xlow == to_xlow */ 01449 else if(to_xhigh > from_xhigh) 01450 { /* Draw from right edge of one to other */ 01451 x1 = tile_x[from_xhigh] + tile_width; 01452 x2 = tile_x[from_xhigh + 1]; 01453 } 01454 else if(from_xhigh > to_xhigh) 01455 { 01456 x1 = tile_x[to_xhigh + 1]; 01457 x2 = tile_x[to_xhigh] + tile_width; 01458 } 01459 else 01460 { /* Complete overlap: start and end both align. Draw outside the sbox */ 01461 x1 = tile_x[from_xlow]; 01462 x2 = tile_x[from_xlow] + tile_width; 01463 } 01464 } 01465 } 01466 /* UDSD Modification by WMF End */ 01467 drawline(x1, y1, x2, y2); 01468 01469 if(draw_rr_toggle == DRAW_ALL_RR) 01470 draw_rr_switch(x1, y1, x2, y2, switch_inf[switch_type].buffered); 01471 } 01472 01473 01474 /** Draws a connection between two y-channel segments. Passing in the track 01475 * numbers allows this routine to be used for both rr_graph and routing 01476 * drawing. 01477 */ 01478 static void 01479 draw_chany_to_chany_edge(int from_node, 01480 int from_track, 01481 int to_node, 01482 int to_track, 01483 short switch_type) 01484 { 01485 float x1, x2, y1, y2; 01486 int from_x, to_x, from_ylow, to_ylow, from_yhigh, to_yhigh; 01487 01488 from_x = rr_node[from_node].xlow; 01489 from_ylow = rr_node[from_node].ylow; 01490 from_yhigh = rr_node[from_node].yhigh; 01491 to_x = rr_node[to_node].xlow; 01492 to_ylow = rr_node[to_node].ylow; 01493 to_yhigh = rr_node[to_node].yhigh; 01494 01495 /* (x1, y1) point on from_node, (x2, y2) point on to_node. */ 01496 01497 x1 = tile_x[from_x] + tile_width + 1 + from_track; 01498 x2 = tile_x[to_x] + tile_width + 1 + to_track; 01499 01500 if(to_yhigh < from_ylow) 01501 { /* From upper to lower */ 01502 y1 = tile_y[from_ylow]; 01503 y2 = tile_y[to_yhigh] + tile_width; 01504 } 01505 else if(to_ylow > from_yhigh) 01506 { /* From lower to upper */ 01507 y1 = tile_y[from_yhigh] + tile_width; 01508 y2 = tile_y[to_ylow]; 01509 } 01510 01511 /* Segments overlap in the channel. Figure out best way to draw. Have to * 01512 * make sure the drawing is symmetric in the from rr and to rr so the edges * 01513 * will be drawn on top of each other for bidirectional connections. */ 01514 01515 /* UDSD Modification by WMF Begin */ 01516 else 01517 { 01518 if(rr_node[to_node].direction != BI_DIRECTION) 01519 { 01520 if(to_track % 2 == 0) 01521 { /* INC wire starts at bottom edge */ 01522 assert(from_ylow < to_ylow); 01523 y2 = tile_y[to_ylow]; 01524 /* since no U-turns from_track must be INC as well */ 01525 y1 = tile_y[to_ylow - 1] + tile_width; 01526 } 01527 else 01528 { /* DEC wire starts at top edge */ 01529 if(!(from_yhigh > to_yhigh)) 01530 { 01531 printf 01532 ("from_yhigh (%d) !> to_yhigh (%d).\n", 01533 from_yhigh, to_yhigh); 01534 printf 01535 ("from is (%d, %d) to (%d, %d) track %d.\n", 01536 rr_node[from_node].xhigh, 01537 rr_node[from_node].yhigh, 01538 rr_node[from_node].xlow, 01539 rr_node[from_node].ylow, 01540 rr_node[from_node].ptc_num); 01541 printf 01542 ("to is (%d, %d) to (%d, %d) track %d.\n", 01543 rr_node[to_node].xhigh, 01544 rr_node[to_node].yhigh, 01545 rr_node[to_node].xlow, 01546 rr_node[to_node].ylow, 01547 rr_node[to_node].ptc_num); 01548 exit(1); 01549 } 01550 y2 = tile_y[to_yhigh] + tile_width; 01551 y1 = tile_y[to_yhigh + 1]; 01552 } 01553 } 01554 else 01555 { 01556 if(to_ylow < from_ylow) 01557 { /* Draw from bottom edge of one to other. */ 01558 y1 = tile_y[from_ylow]; 01559 y2 = tile_y[from_ylow - 1] + tile_width; 01560 } 01561 else if(from_ylow < to_ylow) 01562 { 01563 y1 = tile_y[to_ylow - 1] + tile_width; 01564 y2 = tile_y[to_ylow]; 01565 } 01566 else if(to_yhigh > from_yhigh) 01567 { /* Draw from top edge of one to other. */ 01568 y1 = tile_y[from_yhigh] + tile_width; 01569 y2 = tile_y[from_yhigh + 1]; 01570 } 01571 else if(from_yhigh > to_yhigh) 01572 { 01573 y1 = tile_y[to_yhigh + 1]; 01574 y2 = tile_y[to_yhigh] + tile_width; 01575 } 01576 else 01577 { /* Complete overlap: start and end both align. Draw outside the sbox */ 01578 y1 = tile_y[from_ylow]; 01579 y2 = tile_y[from_ylow] + tile_width; 01580 } 01581 } 01582 } 01583 /* UDSD Modification by WMF End */ 01584 drawline(x1, y1, x2, y2); 01585 01586 if(draw_rr_toggle == DRAW_ALL_RR) 01587 draw_rr_switch(x1, y1, x2, y2, switch_inf[switch_type].buffered); 01588 } 01589 01590 01591 /** Draws a buffer (triangle) or pass transistor (circle) on the edge 01592 * connecting from to to, depending on the status of buffered. The drawing 01593 * is closest to the from_node, since it reflects the switch type of from. 01594 */ 01595 static void 01596 draw_rr_switch(float from_x, 01597 float from_y, 01598 float to_x, 01599 float to_y, 01600 boolean buffered) 01601 { 01602 const float switch_rad = 0.15; 01603 float magnitude, xcen, ycen, xdelta, ydelta, xbaseline, ybaseline; 01604 float xunit, yunit; 01605 t_point poly[3]; 01606 01607 xcen = from_x + (to_x - from_x) / 10.; 01608 ycen = from_y + (to_y - from_y) / 10.; 01609 01610 if(!buffered) 01611 { /* Draw a circle for a pass transistor */ 01612 drawarc(xcen, ycen, switch_rad, 0., 360.); 01613 } 01614 else 01615 { /* Buffer */ 01616 xdelta = to_x - from_x; 01617 ydelta = to_y - from_y; 01618 magnitude = sqrt(xdelta * xdelta + ydelta * ydelta); 01619 xunit = xdelta / magnitude; 01620 yunit = ydelta / magnitude; 01621 poly[0].x = xcen + xunit * switch_rad; 01622 poly[0].y = ycen + yunit * switch_rad; 01623 xbaseline = xcen - xunit * switch_rad; 01624 ybaseline = ycen - yunit * switch_rad; 01625 01626 /* Recall: perpendicular vector to the unit vector along the switch (xv, yv) * 01627 * is (yv, -xv). */ 01628 01629 poly[1].x = xbaseline + yunit * switch_rad; 01630 poly[1].y = ybaseline - xunit * switch_rad; 01631 poly[2].x = xbaseline - yunit * switch_rad; 01632 poly[2].y = ybaseline + xunit * switch_rad; 01633 fillpoly(poly, 3); 01634 } 01635 } 01636 01637 01638 /** Draws an IPIN or OPIN rr_node. Note that the pin can appear on more 01639 * than one side of a clb. Also note that this routine can change the 01640 * current color to BLACK. 01641 */ 01642 static void 01643 draw_rr_pin(int inode, 01644 enum color_types color) 01645 { 01646 int ipin, i, j, iside, iclass, ioff; 01647 float xcen, ycen; 01648 char str[BUFSIZE]; 01649 t_type_ptr type; 01650 01651 i = rr_node[inode].xlow; 01652 j = rr_node[inode].ylow; 01653 ipin = rr_node[inode].ptc_num; 01654 type = grid[i][j].type; 01655 ioff = grid[i][j].offset; 01656 01657 setcolor(color); 01658 iclass = type->pin_class[ipin]; 01659 /* TODO: This is where we can hide fringe physical pins and also identify globals (hide, color, show) */ 01660 for(iside = 0; iside < 4; iside++) 01661 { 01662 if(type->pinloc[grid[i][j].offset][iside][ipin]) 01663 { /* Pin exists on this side. */ 01664 get_rr_pin_draw_coords(inode, iside, ioff, &xcen, &ycen); 01665 fillrect(xcen - pin_size, ycen - pin_size, 01666 xcen + pin_size, ycen + pin_size); 01667 sprintf(str, "%d", ipin); 01668 setcolor(BLACK); 01669 drawtext(xcen, ycen, str, 2 * pin_size); 01670 setcolor(color); 01671 } 01672 } 01673 } 01674 01675 01676 /** Returns the coordinates at which the center of this pin should be drawn. 01677 * inode gives the node number, and iside gives the side of the clb or pad 01678 * the physical pin is on. 01679 */ 01680 static void 01681 get_rr_pin_draw_coords(int inode, 01682 int iside, 01683 int ioff, 01684 float *xcen, 01685 float *ycen) 01686 { 01687 01688 int i, j, k, ipin, pins_per_sub_tile; 01689 float offset, xc, yc, step; 01690 t_type_ptr type; 01691 01692 i = rr_node[inode].xlow; 01693 j = rr_node[inode].ylow + ioff; /* Need correct tile of block */ 01694 01695 xc = tile_x[i]; 01696 yc = tile_y[j]; 01697 01698 ipin = rr_node[inode].ptc_num; 01699 type = grid[i][j].type; 01700 pins_per_sub_tile = grid[i][j].type->num_pins / grid[i][j].type->capacity; 01701 k = ipin / pins_per_sub_tile; 01702 01703 /* Since pins numbers go across all sub_tiles in a block in order 01704 * we can treat as a block box for this step */ 01705 01706 /* For each sub_tile we need and extra padding space */ 01707 step = (float)(tile_width) / (float)(type->num_pins + type->capacity); 01708 offset = (ipin + k + 1) * step; 01709 01710 switch (iside) 01711 { 01712 case LEFT: 01713 yc += offset; 01714 break; 01715 01716 case RIGHT: 01717 xc += tile_width; 01718 yc += offset; 01719 break; 01720 01721 case BOTTOM: 01722 xc += offset; 01723 break; 01724 01725 case TOP: 01726 xc += offset; 01727 yc += tile_width; 01728 break; 01729 01730 default: 01731 printf("Error in get_rr_pin_draw_coords: Unexpected iside %d.\n", 01732 iside); 01733 exit(1); 01734 break; 01735 } 01736 01737 *xcen = xc; 01738 *ycen = yc; 01739 } 01740 01741 01742 /** Draws the nets in the positions fixed by the router. If draw_net_type is 01743 * ALL_NETS, draw all the nets. If it is HIGHLIGHTED, draw only the nets 01744 * that are not coloured black (useful for drawing over the rr_graph). 01745 * Next free track in each channel segment if routing is GLOBAL. 01746 */ 01747 static void 01748 drawroute(enum e_draw_net_type draw_net_type) 01749 { 01750 01751 static int **chanx_track = NULL; /* [1..nx][0..ny] */ 01752 static int **chany_track = NULL; /* [0..nx][1..ny] */ 01753 01754 int inet, i, j, inode, prev_node, prev_track, itrack; 01755 short switch_type; 01756 struct s_trace *tptr; 01757 t_rr_type rr_type, prev_type; 01758 01759 01760 if(draw_route_type == GLOBAL) 01761 { 01762 /* Allocate some temporary storage if it's not already available. */ 01763 if(chanx_track == NULL) 01764 { 01765 chanx_track = 01766 (int **)alloc_matrix(1, nx, 0, ny, sizeof(int)); 01767 } 01768 01769 if(chany_track == NULL) 01770 { 01771 chany_track = 01772 (int **)alloc_matrix(0, nx, 1, ny, sizeof(int)); 01773 } 01774 01775 for(i = 1; i <= nx; i++) 01776 for(j = 0; j <= ny; j++) 01777 chanx_track[i][j] = (-1); 01778 01779 for(i = 0; i <= nx; i++) 01780 for(j = 1; j <= ny; j++) 01781 chany_track[i][j] = (-1); 01782 } 01783 01784 setlinestyle(SOLID); 01785 01786 /* Now draw each net, one by one. */ 01787 01788 for(inet = 0; inet < num_nets; inet++) 01789 { 01790 if(clb_net[inet].is_global) /* Don't draw global nets. */ 01791 continue; 01792 01793 if(trace_head[inet] == NULL) /* No routing. Skip. (Allows me to draw */ 01794 continue; /* partially complete routes). */ 01795 01796 if(draw_net_type == HIGHLIGHTED && net_color[inet] == BLACK) 01797 continue; 01798 01799 setcolor(net_color[inet]); 01800 tptr = trace_head[inet]; /* SOURCE to start */ 01801 inode = tptr->index; 01802 rr_type = rr_node[inode].type; 01803 01804 01805 for(;;) 01806 { 01807 prev_node = inode; 01808 prev_type = rr_type; 01809 switch_type = tptr->iswitch; 01810 tptr = tptr->next; 01811 inode = tptr->index; 01812 rr_type = rr_node[inode].type; 01813 01814 switch (rr_type) 01815 { 01816 01817 case OPIN: 01818 draw_rr_pin(inode, net_color[inet]); 01819 break; 01820 01821 case IPIN: 01822 draw_rr_pin(inode, net_color[inet]); 01823 prev_track = 01824 get_track_num(prev_node, chanx_track, 01825 chany_track); 01826 draw_pin_to_chan_edge(inode, prev_node); 01827 break; 01828 01829 case CHANX: 01830 if(draw_route_type == GLOBAL) 01831 chanx_track[rr_node[inode]. 01832 xlow][rr_node[inode].ylow]++; 01833 01834 itrack = 01835 get_track_num(inode, chanx_track, 01836 chany_track); 01837 draw_rr_chanx(inode, itrack); 01838 01839 switch (prev_type) 01840 { 01841 01842 case CHANX: 01843 prev_track = 01844 get_track_num(prev_node, chanx_track, 01845 chany_track); 01846 draw_chanx_to_chanx_edge(prev_node, 01847 prev_track, 01848 inode, itrack, 01849 switch_type); 01850 break; 01851 01852 case CHANY: 01853 prev_track = 01854 get_track_num(prev_node, chanx_track, 01855 chany_track); 01856 draw_chanx_to_chany_edge(inode, itrack, 01857 prev_node, 01858 prev_track, 01859 FROM_Y_TO_X, 01860 switch_type); 01861 break; 01862 01863 case OPIN: 01864 draw_pin_to_chan_edge(prev_node, inode); 01865 break; 01866 01867 default: 01868 printf 01869 ("Error in drawroute: Unexpected connection from an \n" 01870 "rr_node of type %d to one of type %d.\n", 01871 prev_type, rr_type); 01872 exit(1); 01873 } 01874 01875 break; 01876 01877 case CHANY: 01878 if(draw_route_type == GLOBAL) 01879 chany_track[rr_node[inode]. 01880 xlow][rr_node[inode].ylow]++; 01881 01882 itrack = 01883 get_track_num(inode, chanx_track, 01884 chany_track); 01885 draw_rr_chany(inode, itrack); 01886 01887 switch (prev_type) 01888 { 01889 01890 case CHANX: 01891 prev_track = 01892 get_track_num(prev_node, chanx_track, 01893 chany_track); 01894 draw_chanx_to_chany_edge(prev_node, 01895 prev_track, 01896 inode, itrack, 01897 FROM_X_TO_Y, 01898 switch_type); 01899 break; 01900 01901 case CHANY: 01902 prev_track = 01903 get_track_num(prev_node, chanx_track, 01904 chany_track); 01905 draw_chany_to_chany_edge(prev_node, 01906 prev_track, 01907 inode, itrack, 01908 switch_type); 01909 break; 01910 01911 case OPIN: 01912 draw_pin_to_chan_edge(prev_node, inode); 01913 01914 break; 01915 01916 default: 01917 printf 01918 ("Error in drawroute: Unexpected connection from an \n" 01919 "rr_node of type %d to one of type %d.\n", 01920 prev_type, rr_type); 01921 exit(1); 01922 } 01923 01924 break; 01925 01926 default: 01927 break; 01928 01929 } 01930 01931 if(rr_type == SINK) 01932 { /* Skip the next segment */ 01933 tptr = tptr->next; 01934 if(tptr == NULL) 01935 break; 01936 inode = tptr->index; 01937 rr_type = rr_node[inode].type; 01938 } 01939 01940 } /* End loop over traceback. */ 01941 } /* End for (each net) */ 01942 } 01943 01944 01945 /** Returns the track number of this routing resource node. */ 01946 static int 01947 get_track_num(int inode, 01948 int **chanx_track, 01949 int **chany_track) 01950 { 01951 int i, j; 01952 t_rr_type rr_type; 01953 01954 if(draw_route_type == DETAILED) 01955 return (rr_node[inode].ptc_num); 01956 01957 /* GLOBAL route stuff below. */ 01958 01959 rr_type = rr_node[inode].type; 01960 i = rr_node[inode].xlow; /* NB: Global rr graphs must have only unit */ 01961 j = rr_node[inode].ylow; /* length channel segments. */ 01962 01963 switch (rr_type) 01964 { 01965 case CHANX: 01966 return (chanx_track[i][j]); 01967 01968 case CHANY: 01969 return (chany_track[i][j]); 01970 01971 default: 01972 printf 01973 ("Error in get_track_num: unexpected node type %d for node %d." 01974 "\n", rr_type, inode); 01975 exit(1); 01976 } 01977 } 01978 01979 static void 01980 highlight_nets(char *message) 01981 { 01982 int inet; 01983 struct s_trace *tptr; 01984 01985 for(inet = 0; inet < num_nets; inet++) 01986 { 01987 for(tptr = trace_head[inet]; tptr != NULL; tptr = tptr->next) 01988 { 01989 if(rr_node_color[tptr->index] != BLACK) 01990 { 01991 net_color[inet] = rr_node_color[tptr->index]; 01992 sprintf(message, "%s || Net:%d %d", message,inet, 01993 trace_head[inet]->index 01994 ); 01995 break; 01996 } 01997 } 01998 } 01999 update_message (message); 02000 } 02001 02002 static void 02003 highlight_rr_nodes(float x, float y) 02004 { 02005 int inode; 02006 int hit = 0; 02007 char message[250] = ""; 02008 int edge; 02009 02010 if(draw_rr_toggle == DRAW_NO_RR && ! show_nets) 02011 { 02012 update_message(default_message); 02013 drawscreen(); 02014 return; 02015 } 02016 02017 for(inode = 0; inode < num_rr_nodes; inode++) 02018 { 02019 if(x >= x_rr_node_left[inode] && 02020 x <= x_rr_node_right[inode] && 02021 y >= y_rr_node_bottom[inode] && 02022 y <= y_rr_node_top[inode]) 02023 { 02024 t_rr_type rr_type = rr_node[inode].type; 02025 int xlow = rr_node[inode].xlow; 02026 int xhigh = rr_node[inode].xhigh; 02027 int ylow = rr_node[inode].ylow; 02028 int yhigh = rr_node[inode].yhigh; 02029 int ptc_num = rr_node[inode].ptc_num; 02030 rr_node_color[inode] = MAGENTA; 02031 sprintf(message, "%s%s %d: %s (%d,%d) -> (%d,%d) track: %d", message, 02032 (hit?" | ":""), inode, name_type[rr_type], xlow,ylow 02033 , xhigh, yhigh, ptc_num 02034 ); 02035 02036 #ifdef DEBUG 02037 print_rr_node(stdout, rr_node, inode); 02038 #endif 02039 for(edge = 0; edge < rr_node[inode].num_edges; edge++) 02040 { 02041 if(rr_node_color[rr_node[inode].edges[edge]] == BLACK && 02042 rr_node[rr_node[inode].edges[edge]].capacity > 02043 rr_node[rr_node[inode].edges[edge]].occ) 02044 rr_node_color[rr_node[inode].edges[edge]] = GREEN; 02045 else if(rr_node_color[rr_node[inode].edges[edge]] == BLACK && 02046 rr_node[rr_node[inode].edges[edge]].capacity == 02047 rr_node[rr_node[inode].edges[edge]].occ) 02048 rr_node_color[rr_node[inode].edges[edge]] = BLUE; 02049 02050 } 02051 hit = 1; 02052 } 02053 } 02054 02055 02056 if (!hit) { 02057 update_message(default_message); 02058 drawscreen(); 02059 return; 02060 } 02061 02062 if(show_nets) 02063 { 02064 highlight_nets(message); 02065 }else 02066 update_message(message); 02067 drawscreen(); 02068 } 02069 02070 /** This routine is called when the user clicks in the graphics area. 02071 * It determines if a clb was clicked on. If one was, it is 02072 * highlighted in green, it's fanin nets and clbs are highlighted in 02073 * blue and it's fanout is highlighted in red. If no clb was 02074 * clicked on (user clicked on white space) any old highlighting is 02075 * removed. Note that even though global nets are not drawn, their 02076 * fanins and fanouts are highlighted when you click on a block 02077 * attached to them. 02078 */ 02079 static void 02080 highlight_blocks(float x, 02081 float y) 02082 { 02083 int i, j, k, hit, bnum, ipin, netnum, fanblk; 02084 int iclass; 02085 float io_step; 02086 t_type_ptr type; 02087 char msg[BUFSIZE]; 02088 02089 deselect_all(); 02090 02091 hit = i = j = k = 0; 02092 02093 for(i = 0; i <= (nx + 1) && !hit; i++) 02094 { 02095 if(x <= tile_x[i] + tile_width) 02096 { 02097 if(x >= tile_x[i]){ 02098 for(j = 0; j <= (ny + 1) && !hit; j++) 02099 { 02100 if(grid[i][j].offset != 0) 02101 continue; 02102 type = grid[i][j].type; 02103 if(y <= tile_y[j + type->height - 1] + tile_width) 02104 { 02105 if(y >= tile_y[j]) 02106 hit = 1; 02107 } 02108 } 02109 02110 } 02111 } 02112 } 02113 i--; 02114 j--; 02115 02116 if(!hit) 02117 { 02118 highlight_rr_nodes(x, y); 02119 /* update_message(default_message); 02120 drawscreen(); */ 02121 return; 02122 } 02123 type = grid[i][j].type; 02124 hit = 0; 02125 02126 if(EMPTY_TYPE == type) 02127 { 02128 update_message(default_message); 02129 drawscreen(); 02130 return; 02131 } 02132 02133 /* The user selected the clb at location (i,j). */ 02134 io_step = tile_width / type->capacity; 02135 02136 if((i < 1) || (i > nx)) /* Vertical columns of IOs */ 02137 k = (int)((y - tile_y[j]) / io_step); 02138 else 02139 k = (int)((x - tile_x[i]) / io_step); 02140 02141 assert(k < type->capacity); 02142 if(grid[i][j].blocks[k] == EMPTY) 02143 { 02144 update_message(default_message); 02145 drawscreen(); 02146 return; 02147 } 02148 bnum = grid[i][j].blocks[k]; 02149 02150 /* Highlight fanin and fanout. */ 02151 02152 for(k = 0; k < type->num_pins; k++) 02153 { /* Each pin on a CLB */ 02154 netnum = block[bnum].nets[k]; 02155 02156 if(netnum == OPEN) 02157 continue; 02158 02159 iclass = type->pin_class[k]; 02160 02161 if(type->class_inf[iclass].type == DRIVER) 02162 { /* Fanout */ 02163 net_color[netnum] = RED; 02164 for(ipin = 1; ipin <= clb_net[netnum].num_sinks; ipin++) 02165 { 02166 fanblk = clb_net[netnum].node_block[ipin]; 02167 block_color[fanblk] = RED; 02168 } 02169 } 02170 else 02171 { /* This net is fanin to the block. */ 02172 net_color[netnum] = BLUE; 02173 fanblk = clb_net[netnum].node_block[0]; /* DRIVER to net */ 02174 block_color[fanblk] = BLUE; 02175 } 02176 } 02177 02178 block_color[bnum] = GREEN; /* Selected block. */ 02179 02180 sprintf(msg, "Block %d (%s) at (%d, %d) selected.", bnum, 02181 block[bnum].name, i, j); 02182 update_message(msg); 02183 drawscreen(); /* Need to erase screen. */ 02184 } 02185 02186 02187 /** Sets the color of all clbs and nets to the default. */ 02188 static void 02189 deselect_all(void) 02190 { 02191 int i; 02192 02193 /* Create some colour highlighting */ 02194 for(i = 0; i < num_blocks; i++) { 02195 if(block[i].type->index < 3) { 02196 block_color[i] = LIGHTGREY; 02197 } else if(block[i].type->index < 3 + MAX_BLOCK_COLOURS) { 02198 block_color[i] = BISQUE + MAX_BLOCK_COLOURS + block[i].type->index - 3; 02199 } else { 02200 block_color[i] = BISQUE + 2 * MAX_BLOCK_COLOURS - 1; 02201 } 02202 } 02203 02204 for(i = 0; i < num_nets; i++) 02205 net_color[i] = BLACK; 02206 02207 for (i = 0; i < num_rr_nodes; i++) 02208 rr_node_color[i] = BLACK; 02209 } 02210 02211 02212 /* UDSD by AY Start */ 02213 static void 02214 draw_triangle_along_line(float xend, 02215 float yend, 02216 float x1, 02217 float x2, 02218 float y1, 02219 float y2) 02220 { 02221 float switch_rad = 0.15; 02222 float xdelta, ydelta; 02223 float magnitude; 02224 float xunit, yunit; 02225 float xbaseline, ybaseline; 02226 t_point poly[3]; 02227 02228 xdelta = x2 - x1; 02229 ydelta = y2 - y1; 02230 magnitude = sqrt(xdelta * xdelta + ydelta * ydelta); 02231 xunit = xdelta / magnitude; 02232 yunit = ydelta / magnitude; 02233 02234 poly[0].x = xend + xunit * switch_rad; 02235 poly[0].y = yend + yunit * switch_rad; 02236 xbaseline = xend - xunit * switch_rad; 02237 ybaseline = yend - yunit * switch_rad; 02238 poly[1].x = xbaseline + yunit * switch_rad; 02239 poly[1].y = ybaseline - xunit * switch_rad; 02240 poly[2].x = xbaseline - yunit * switch_rad; 02241 poly[2].y = ybaseline + xunit * switch_rad; 02242 02243 fillpoly(poly, 3); 02244 } 02245 02246 02247 /** This routine draws an edge from the pin_node to the chan_node (CHANX or 02248 * CHANY). The connection is made to the nearest end of the track instead 02249 * of perpundicular to the track to symbolize a single-drive connection. 02250 * If mark_conn is TRUE, draw a box where the pin connects to the track 02251 * (useful for drawing the rr graph) 02252 */ 02253 static void 02254 draw_pin_to_chan_edge(int pin_node, 02255 int chan_node) 02256 { 02257 /* TODO: Fix this for global routing, currently for detailed only */ 02258 02259 t_rr_type chan_type; 02260 int grid_x, grid_y, pin_num, chan_xlow, chan_ylow, ioff, height; 02261 float x1, x2, y1, y2; 02262 int start, end, i; 02263 int itrack; 02264 float xend, yend; 02265 float draw_pin_off; 02266 enum e_direction direction; 02267 enum e_side iside; 02268 t_type_ptr type; 02269 02270 direction = rr_node[chan_node].direction; 02271 grid_x = rr_node[pin_node].xlow; 02272 grid_y = rr_node[pin_node].ylow; 02273 pin_num = rr_node[pin_node].ptc_num; 02274 chan_type = rr_node[chan_node].type; 02275 itrack = rr_node[chan_node].ptc_num; 02276 type = grid[grid_x][grid_y].type; 02277 02278 ioff = grid[grid_x][grid_y].offset; 02279 /* large block begins at primary tile (offset == 0) */ 02280 grid_y = grid_y - ioff; 02281 height = grid[grid_x][grid_y].type->height; 02282 chan_ylow = rr_node[chan_node].ylow; 02283 chan_xlow = rr_node[chan_node].xlow; 02284 start = -1; 02285 end = -1; 02286 02287 02288 switch (chan_type) 02289 { 02290 02291 case CHANX: 02292 start = rr_node[chan_node].xlow; 02293 end = rr_node[chan_node].xhigh; 02294 if(is_opin(pin_num, type)) 02295 { 02296 if(direction == INC_DIRECTION) 02297 { 02298 end = rr_node[chan_node].xlow; 02299 } 02300 else if(direction == DEC_DIRECTION) 02301 { 02302 start = rr_node[chan_node].xhigh; 02303 } 02304 } 02305 02306 start = max(start, grid_x); 02307 end = min(end, grid_x); /* Width is 1 always */ 02308 assert(end >= start); /* Make sure we are nearby */ 02309 02310 if((grid_y + height - 1) == chan_ylow) 02311 { 02312 iside = TOP; 02313 ioff = height - 1; 02314 draw_pin_off = pin_size; 02315 } 02316 else 02317 { 02318 assert((grid_y - 1) == chan_ylow); 02319 02320 iside = BOTTOM; 02321 ioff = 0; 02322 draw_pin_off = -pin_size; 02323 } 02324 assert(grid[grid_x][grid_y].type->pinloc[ioff][iside][pin_num]); 02325 02326 get_rr_pin_draw_coords(pin_node, iside, ioff, &x1, &y1); 02327 y1 += draw_pin_off; 02328 02329 y2 = tile_y[rr_node[chan_node].ylow] + tile_width + 1. + itrack; 02330 x2 = x1; 02331 if(is_opin(pin_num, type)) 02332 { 02333 if(direction == INC_DIRECTION) 02334 { 02335 x2 = tile_x[rr_node[chan_node].xlow]; 02336 } 02337 else if(direction == DEC_DIRECTION) 02338 { 02339 x2 = tile_x[rr_node[chan_node].xhigh] + 02340 tile_width; 02341 } 02342 } 02343 break; 02344 02345 case CHANY: 02346 start = rr_node[chan_node].ylow; 02347 end = rr_node[chan_node].yhigh; 02348 if(is_opin(pin_num, type)) 02349 { 02350 if(direction == INC_DIRECTION) 02351 { 02352 end = rr_node[chan_node].ylow; 02353 } 02354 else if(direction == DEC_DIRECTION) 02355 { 02356 start = rr_node[chan_node].yhigh; 02357 } 02358 } 02359 02360 start = max(start, grid_y); 02361 end = min(end, (grid_y + height - 1)); /* Width is 1 always */ 02362 assert(end >= start); /* Make sure we are nearby */ 02363 02364 if((grid_x) == chan_xlow) 02365 { 02366 iside = RIGHT; 02367 draw_pin_off = pin_size; 02368 } 02369 else 02370 { 02371 assert((grid_x - 1) == chan_xlow); 02372 iside = LEFT; 02373 draw_pin_off = -pin_size; 02374 } 02375 for(i = start; i <= end; i++) 02376 { 02377 ioff = i - grid_y; 02378 assert(ioff >= 0 && ioff < type->height); 02379 /* Once we find the location, break out, this will leave ioff pointing 02380 * to the correct offset. If an offset is not found, the assertion after 02381 * this will fail. With the correct routing graph, the assertion will not 02382 * be triggered. This also takes care of connecting a wire once to multiple 02383 * physical pins on the same side. */ 02384 if(grid[grid_x][grid_y].type-> 02385 pinloc[ioff][iside][pin_num]) 02386 { 02387 break; 02388 } 02389 } 02390 assert(grid[grid_x][grid_y].type->pinloc[ioff][iside][pin_num]); 02391 02392 get_rr_pin_draw_coords(pin_node, iside, ioff, &x1, &y1); 02393 x1 += draw_pin_off; 02394 02395 x2 = tile_x[chan_xlow] + tile_width + 1 + itrack; 02396 y2 = y1; 02397 if(is_opin(pin_num, type)) 02398 { 02399 if(direction == INC_DIRECTION) 02400 { 02401 y2 = tile_y[rr_node[chan_node].ylow]; 02402 } 02403 else if(direction == DEC_DIRECTION) 02404 { 02405 y2 = tile_y[rr_node[chan_node].yhigh] + 02406 tile_width; 02407 } 02408 } 02409 break; 02410 02411 default: 02412 printf 02413 ("Error in draw_pin_to_chan_edge: invalid channel node %d.\n", 02414 chan_node); 02415 exit(1); 02416 } 02417 02418 drawline(x1, y1, x2, y2); 02419 if(direction == BI_DIRECTION || !is_opin(pin_num, type)) 02420 { 02421 draw_x(x2, y2, 0.7 * pin_size); 02422 } 02423 else 02424 { 02425 xend = x2 + (x1 - x2) / 10.; 02426 yend = y2 + (y1 - y2) / 10.; 02427 draw_triangle_along_line(xend, yend, x1, x2, y1, y2); 02428 } 02429 } 02430 02431 /* UDSD by AY End */