From eef1312325bd02420f56b1d00681dcd0654b1501 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 24 May 2019 12:54:10 -0600 Subject: [PATCH] updated bitstream to use new RRSwitchBlock as well as the report timing engine --- .../SRC/fpga_spice_include/my_free_fwd.h | 6 + .../fpga_spice_include/read_xml_spice_util.h | 6 +- .../vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h | 2 +- .../SRC/fpga_x2p/bitstream/fpga_bitstream.c | 3 +- .../bitstream/fpga_bitstream_routing.c | 322 ++++++++--- .../bitstream/fpga_bitstream_routing.h | 3 +- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 3 +- .../verilog/verilog_compact_netlist.c | 5 +- .../fpga_x2p/verilog/verilog_report_timing.c | 523 ++++++++++++++++-- .../fpga_x2p/verilog/verilog_report_timing.h | 3 +- .../SRC/fpga_x2p/verilog/verilog_tcl_utils.c | 249 +++++++++ .../SRC/fpga_x2p/verilog/verilog_tcl_utils.h | 28 + 12 files changed, 995 insertions(+), 158 deletions(-) create mode 100644 vpr7_x2p/libarchfpga/SRC/fpga_spice_include/my_free_fwd.h diff --git a/vpr7_x2p/libarchfpga/SRC/fpga_spice_include/my_free_fwd.h b/vpr7_x2p/libarchfpga/SRC/fpga_spice_include/my_free_fwd.h new file mode 100644 index 000000000..8465fd4c3 --- /dev/null +++ b/vpr7_x2p/libarchfpga/SRC/fpga_spice_include/my_free_fwd.h @@ -0,0 +1,6 @@ +#ifndef MY_FREE_FWD_H +#define MY_FREE_FWD_H + +void my_free(void* ptr); + +#endif diff --git a/vpr7_x2p/libarchfpga/SRC/fpga_spice_include/read_xml_spice_util.h b/vpr7_x2p/libarchfpga/SRC/fpga_spice_include/read_xml_spice_util.h index e670005e2..b54880fd1 100644 --- a/vpr7_x2p/libarchfpga/SRC/fpga_spice_include/read_xml_spice_util.h +++ b/vpr7_x2p/libarchfpga/SRC/fpga_spice_include/read_xml_spice_util.h @@ -1,6 +1,9 @@ +#ifndef READ_XML_SPICE_UTIL_H +#define READ_XML_SPICE_UTIL_H /* Declaration of Subroutines */ -void my_free(void* ptr); +#include "my_free_fwd.h" + void InitSpiceMeasParams(t_spice_meas_params* meas_params); void FreeSpiceMeasParams(t_spice_meas_params* meas_params); void InitSpiceStimulateParams(t_spice_stimulate_params* stimulate_params); @@ -18,3 +21,4 @@ void FreeSpice(t_spice* spice); void FreeSpiceMuxArch(t_spice_mux_arch* spice_mux_arch); void FreeSramInf(t_sram_inf* sram_inf); +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h index 9e5463b67..8f53d82f2 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h @@ -1,7 +1,7 @@ #ifndef FPGA_X2P_UTILS_H #define FPGA_X2P_UTILS_H -void my_free(void* ptr); +#include "my_free_fwd.h" char* my_gettime(); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream.c b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream.c index 505391f47..78ec729e4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream.c @@ -30,6 +30,7 @@ #include "fpga_x2p_globals.h" #include "fpga_bitstream_pbtypes.h" #include "fpga_bitstream_routing.h" +#include "fpga_bitstream.h" /* Global variables only in file */ static int dumped_num_conf_bits = 0; @@ -351,7 +352,7 @@ void vpr_fpga_generate_bitstream(t_vpr_setup vpr_setup, routing_bitstream_log_file_path = my_strcat(circuit_name, fpga_spice_bitstream_routing_log_file_postfix); fpga_spice_generate_bitstream_routing_resources(routing_bitstream_log_file_path, Arch, &vpr_setup.RoutingArch, *cur_sram_orgz_info, - num_rr_nodes, rr_node, rr_node_indices); + vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy); /* Logic blocks */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.c index 3bbe1f646..d44c80ea8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.c @@ -23,6 +23,7 @@ /* Include SPICE support headers*/ #include "linkedlist.h" +#include "rr_blocks.h" #include "fpga_x2p_types.h" #include "fpga_x2p_utils.h" #include "fpga_x2p_backannotate_utils.h" @@ -32,41 +33,98 @@ /* Include Verilog support headers*/ - +/* Generate bitstream for a multiplexer of a switch block */ static -void fpga_spice_generate_bitstream_routing_chan_subckt(int x, int y, - t_rr_type chan_type, - t_sram_orgz_info* cur_sram_orgz_info, - int LL_num_rr_nodes, t_rr_node* LL_rr_node, - t_ivec*** LL_rr_node_indices, - int num_segment, t_segment_inf* segments) { +void fpga_spice_generate_bitstream_switch_box_mux(FILE* fp, + RRSwitchBlock& rr_sb, + t_sram_orgz_info* cur_sram_orgz_info, + t_rr_node* cur_rr_node, + int mux_size, + t_rr_node** drive_rr_nodes, + int switch_index) { + t_spice_model* verilog_model = NULL; + int mux_level, path_id; + int num_mux_sram_bits = 0; + int* mux_sram_bits = NULL; + + /* Check */ + + /* Check the file handler*/ + if (NULL == fp) { + vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", + __FILE__, __LINE__); + exit(1); + } + + /* Check current rr_node is CHANX or CHANY*/ + assert((CHANX == cur_rr_node->type)||(CHANY == cur_rr_node->type)); + + /* Allocate drive_rr_nodes according to the fan-in*/ + assert((2 == mux_size)||(2 < mux_size)); + + /* Get verilog model*/ + verilog_model = switch_inf[switch_index].spice_model; + + /* Configuration bits for this MUX*/ + path_id = DEFAULT_PATH_ID; + for (int inode = 0; inode < mux_size; ++inode) { + if (drive_rr_nodes[inode] == &(rr_node[cur_rr_node->prev_node])) { + path_id = inode; + break; + } + } + + assert((DEFAULT_PATH_ID == path_id) || + ((DEFAULT_PATH_ID < path_id) &&(path_id < mux_size))); + + /* Depend on both technology and structure of this MUX*/ + switch (verilog_model->design_tech) { + case SPICE_MODEL_DESIGN_CMOS: + decode_cmos_mux_sram_bits(verilog_model, mux_size, path_id, &num_mux_sram_bits, &mux_sram_bits, &mux_level); + break; + case SPICE_MODEL_DESIGN_RRAM: + decode_rram_mux(verilog_model, mux_size, path_id, &num_mux_sram_bits, &mux_sram_bits, &mux_level); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid design technology for verilog model (%s)!\n", + __FILE__, __LINE__, verilog_model->name); + exit(1); + } + + /* Print the encoding in SPICE netlist for debugging */ + fprintf(fp, "***** Switch Block [%lu][%lu] *****\n", + rr_sb.get_x(), rr_sb.get_y()); + fprintf(fp, "***** SRAM bits for MUX[%d], level=%d, select_path_id=%d. *****\n", + verilog_model->cnt, mux_level, path_id); + fprintf(fp, "*****"); + for (int ilevel = 0; ilevel < num_mux_sram_bits; ++ilevel) { + fprintf(fp, "%d", mux_sram_bits[ilevel]); + } + fprintf(fp, "*****\n\n"); + + /* Store the configuraion bit to linked-list */ + add_mux_conf_bits_to_llist(mux_size, cur_sram_orgz_info, + num_mux_sram_bits, mux_sram_bits, + verilog_model); + + /* Synchronize the sram_orgz_info with mem_bits */ + add_mux_conf_bits_to_sram_orgz_info(cur_sram_orgz_info, verilog_model, mux_size); + + /* update sram counter */ + verilog_model->cnt++; + + /* Free */ + my_free(mux_sram_bits); + return; } -/* Print a short interconneciton in switch box - * There are two cases should be noticed. - * 1. The actual fan-in of cur_rr_node is 0. In this case, - the cur_rr_node need to be short connected to itself which is on the opposite side of this switch - * 2. The actual fan-in of cur_rr_node is 0. In this case, - * The cur_rr_node need to connected to the drive_rr_node - */ -static -void fpga_spice_generate_bitstream_switch_box_short_interc(t_sb* cur_sb_info, - t_sram_orgz_info* cur_sram_orgz_info, - int chan_side, - t_rr_node* cur_rr_node, - int actual_fan_in, - t_rr_node* drive_rr_node) { - - return; -} /* Print the SPICE netlist of multiplexer that drive this rr_node */ static void fpga_spice_generate_bitstream_switch_box_mux(FILE* fp, t_sb* cur_sb_info, t_sram_orgz_info* cur_sram_orgz_info, - int chan_side, t_rr_node* cur_rr_node, int mux_size, t_rr_node** drive_rr_nodes, @@ -151,6 +209,52 @@ void fpga_spice_generate_bitstream_switch_box_mux(FILE* fp, return; } +static +void fpga_spice_generate_bitstream_switch_box_interc(FILE* fp, + RRSwitchBlock& rr_sb, + t_sram_orgz_info* cur_sram_orgz_info, + enum e_side chan_side, + t_rr_node* cur_rr_node) { + int num_drive_rr_nodes = 0; + t_rr_node** drive_rr_nodes = NULL; + + /* Check */ + /* Check the file handler*/ + if (NULL == fp) { + vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", + __FILE__, __LINE__); + exit(1); + } + + /* Determine if the interc lies inside a channel wire, that is interc between segments */ + /* Check each num_drive_rr_nodes, see if they appear in the cur_sb_info */ + if (true == rr_sb.is_node_imply_short_connection(cur_rr_node)) { + /* Double check if the interc lies inside a channel wire, that is interc between segments */ + assert(true == rr_sb.is_node_exist_opposite_side(cur_rr_node, chan_side)); + num_drive_rr_nodes = 0; + drive_rr_nodes = NULL; + } else { + num_drive_rr_nodes = cur_rr_node->num_drive_rr_nodes; + drive_rr_nodes = cur_rr_node->drive_rr_nodes; + } + + if ( (0 == num_drive_rr_nodes) + || (1 == num_drive_rr_nodes) ) { + /* No bitstream generation required by a special direct connection*/ + } else if (1 < num_drive_rr_nodes) { + /* Print the multiplexer, fan_in >= 2 */ + fpga_spice_generate_bitstream_switch_box_mux(fp, rr_sb, cur_sram_orgz_info, + cur_rr_node, + num_drive_rr_nodes, drive_rr_nodes, + cur_rr_node->drive_switches[DEFAULT_SWITCH_ID]); + } /*Nothing should be done else*/ + + /* Free */ + + return; +} + + static void fpga_spice_generate_bitstream_switch_box_interc(FILE* fp, t_sb* cur_sb_info, @@ -187,20 +291,13 @@ void fpga_spice_generate_bitstream_switch_box_interc(FILE* fp, drive_rr_nodes = cur_rr_node->drive_rr_nodes; } - if (0 == num_drive_rr_nodes) { - /* Print a special direct connection*/ - fpga_spice_generate_bitstream_switch_box_short_interc(cur_sb_info, cur_sram_orgz_info, - chan_side, cur_rr_node, - num_drive_rr_nodes, cur_rr_node); - } else if (1 == num_drive_rr_nodes) { - /* Print a direct connection*/ - fpga_spice_generate_bitstream_switch_box_short_interc(cur_sb_info, cur_sram_orgz_info, - chan_side, cur_rr_node, - num_drive_rr_nodes, drive_rr_nodes[DEFAULT_SWITCH_ID]); + if ( (0 == num_drive_rr_nodes) + || (1 == num_drive_rr_nodes) ) { + /* No bitstream generation required by a special direct connection*/ } else if (1 < num_drive_rr_nodes) { /* Print the multiplexer, fan_in >= 2 */ fpga_spice_generate_bitstream_switch_box_mux(fp, cur_sb_info, cur_sram_orgz_info, - chan_side, cur_rr_node, + cur_rr_node, num_drive_rr_nodes, drive_rr_nodes, cur_rr_node->drive_switches[DEFAULT_SWITCH_ID]); } /*Nothing should be done else*/ @@ -210,6 +307,74 @@ void fpga_spice_generate_bitstream_switch_box_interc(FILE* fp, return; } +/* Task: Generate bitstream for a Switch Box. + * A Switch Box subckt consists of following ports: + * 1. Channel Y [x][y] inputs + * 2. Channel X [x+1][y] inputs + * 3. Channel Y [x][y-1] outputs + * 4. Channel X [x][y] outputs + * 5. Grid[x][y+1] Right side outputs pins + * 6. Grid[x+1][y+1] Left side output pins + * 7. Grid[x+1][y+1] Bottom side output pins + * 8. Grid[x+1][y] Top side output pins + * 9. Grid[x+1][y] Left side output pins + * 10. Grid[x][y] Right side output pins + * 11. Grid[x][y] Top side output pins + * 12. Grid[x][y+1] Bottom side output pins + * + * -------------- -------------- + * | | | | + * | Grid | ChanY | Grid | + * | [x][y+1] | [x][y+1] | [x+1][y+1] | + * | | | | + * -------------- -------------- + * ---------- + * ChanX | Switch | ChanX + * [x][y] | Box | [x+1][y] + * | [x][y] | + * ---------- + * -------------- -------------- + * | | | | + * | Grid | ChanY | Grid | + * | [x][y] | [x][y] | [x+1][y] | + * | | | | + * -------------- -------------- + */ +static +void fpga_spice_generate_bitstream_routing_switch_box_subckt(FILE* fp, + RRSwitchBlock& rr_sb, + t_sram_orgz_info* cur_sram_orgz_info) { + /* Check */ + /* Check the file handler*/ + if (NULL == fp) { + vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", + __FILE__, __LINE__); + exit(1); + } + + /* Put down all the multiplexers */ + for (size_t side = 0; side < rr_sb.get_num_sides(); ++side) { + Side side_manager(side); + for (size_t itrack = 0; itrack < rr_sb.get_chan_width(side_manager.get_side()); ++itrack) { + assert((CHANX == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type) + ||(CHANY == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type)); + /* We care INC_DIRECTION tracks at this side*/ + if (OUT_PORT == rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) { + fpga_spice_generate_bitstream_switch_box_interc(fp, rr_sb, cur_sram_orgz_info, + side_manager.get_side(), + rr_sb.get_chan_node(side_manager.get_side(), itrack)); + } + } + } + + /* Check */ + + /* Free chan_rr_nodes */ + + return; +} + + /* Task: Print the subckt of a Switch Box. * A Switch Box subckt consists of following ports: * 1. Channel Y [x][y] inputs @@ -246,9 +411,7 @@ void fpga_spice_generate_bitstream_switch_box_interc(FILE* fp, static void fpga_spice_generate_bitstream_routing_switch_box_subckt(FILE* fp, t_sb* cur_sb_info, - t_sram_orgz_info* cur_sram_orgz_info, - int LL_num_rr_nodes, t_rr_node* LL_rr_node, - t_ivec*** LL_rr_node_indices) { + t_sram_orgz_info* cur_sram_orgz_info) { int itrack, side; /* Check */ @@ -283,13 +446,6 @@ void fpga_spice_generate_bitstream_routing_switch_box_subckt(FILE* fp, } /* SRC rr_node is the IPIN of a grid.*/ -static -void fpga_spice_generate_bitstream_connection_box_short_interc(t_cb* cur_cb_info, - t_sram_orgz_info* cur_sram_orgz_info, - t_rr_node* src_rr_node) { - return; -} - static void fpga_spice_generate_bitstream_connection_box_mux(FILE* fp, t_cb* cur_cb_info, @@ -401,9 +557,7 @@ void fpga_spice_generate_bitstream_connection_box_interc(FILE* fp, } if (1 == src_rr_node->fan_in) { - /* Print a direct connection*/ - fpga_spice_generate_bitstream_connection_box_short_interc(cur_cb_info, cur_sram_orgz_info, - src_rr_node); + /* No bitstream generation required by a special direct connection*/ } else if (1 < src_rr_node->fan_in) { /* Print the multiplexer, fan_in >= 2 */ fpga_spice_generate_bitstream_connection_box_mux(fp, cur_cb_info, cur_sram_orgz_info, @@ -440,9 +594,7 @@ void fpga_spice_generate_bitstream_connection_box_interc(FILE* fp, static void fpga_spice_generate_bitstream_routing_connection_box_subckt(FILE* fp, t_cb* cur_cb_info, - t_sram_orgz_info* cur_sram_orgz_info, - int LL_num_rr_nodes, t_rr_node* LL_rr_node, - t_ivec*** LL_rr_node_indices) { + t_sram_orgz_info* cur_sram_orgz_info) { int inode, side; int side_cnt = 0; @@ -486,9 +638,7 @@ void fpga_spice_generate_bitstream_routing_resources(char* routing_bitstream_log t_arch arch, t_det_routing_arch* routing_arch, t_sram_orgz_info* cur_sram_orgz_info, - int LL_num_rr_nodes, t_rr_node* LL_rr_node, - t_ivec*** LL_rr_node_indices) { - int ix, iy; + boolean compact_routing_hierarchy) { FILE* fp = NULL; assert(UNI_DIRECTIONAL == routing_arch->directionality); @@ -504,8 +654,8 @@ void fpga_spice_generate_bitstream_routing_resources(char* routing_bitstream_log } /* Two major tasks: - * 1. Generate sub-circuits for Routing Channels - * 2. Generate sub-circuits for Switch Boxes + * 1. Generate bitstreams for Switch Blocks + * 2. Generate bitstreams for Connection Blocks */ /* Now: First task: Routing channels * Sub-circuits are named as chanx[ix][iy] or chany[ix][iy] for horizontal or vertical channels @@ -521,65 +671,55 @@ void fpga_spice_generate_bitstream_routing_resources(char* routing_bitstream_log * For INC_DIRECTION chany, the inputs are at the bottom of channels, the outputs are at the top of channels * For DEC_DIRECTION chany, the inputs are at the top of channels, the outputs are at the bottom of channels */ - /* X - channels [1...nx][0..ny]*/ - vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for Routing Channels - X direction...\n"); - for (iy = 0; iy < (ny + 1); iy++) { - for (ix = 1; ix < (nx + 1); ix++) { - fpga_spice_generate_bitstream_routing_chan_subckt(ix, iy, CHANX, cur_sram_orgz_info, - LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices, - arch.num_segments, arch.Segments); - } - } - /* Y - channels [1...ny][0..nx]*/ - vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for Routing Channels - Y direction...\n"); - for (ix = 0; ix < (nx + 1); ix++) { - for (iy = 1; iy < (ny + 1); iy++) { - fpga_spice_generate_bitstream_routing_chan_subckt(ix, iy, CHANY, cur_sram_orgz_info, - LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices, - arch.num_segments, arch.Segments); - } - } /* Switch Boxes*/ vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for Switch blocks...\n"); - for (ix = 0; ix < (nx + 1); ix++) { - for (iy = 0; iy < (ny + 1); iy++) { - /* vpr_printf(TIO_MESSAGE_INFO, "Writing Switch Boxes[%d][%d]...\n", ix, iy); */ - update_spice_models_routing_index_low(ix, iy, SOURCE, arch.spice->num_spice_model, arch.spice->spice_models); - fpga_spice_generate_bitstream_routing_switch_box_subckt(fp, - &(sb_info[ix][iy]), cur_sram_orgz_info, - LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); - update_spice_models_routing_index_high(ix, iy, SOURCE, arch.spice->num_spice_model, arch.spice->spice_models); + if (TRUE == compact_routing_hierarchy) { + DeviceCoordinator sb_range = device_rr_switch_block.get_switch_block_range(); + for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { + RRSwitchBlock rr_sb = device_rr_switch_block.get_switch_block(ix, iy); + fpga_spice_generate_bitstream_routing_switch_box_subckt(fp, + rr_sb, cur_sram_orgz_info); + } + } + } else { + for (int ix = 0; ix < (nx + 1); ++ix) { + for (int iy = 0; iy < (ny + 1); ++iy) { + /* vpr_printf(TIO_MESSAGE_INFO, "Writing Switch Boxes[%d][%d]...\n", ix, iy); */ + update_spice_models_routing_index_low(ix, iy, SOURCE, arch.spice->num_spice_model, arch.spice->spice_models); + fpga_spice_generate_bitstream_routing_switch_box_subckt(fp, + &(sb_info[ix][iy]), cur_sram_orgz_info); + update_spice_models_routing_index_high(ix, iy, SOURCE, arch.spice->num_spice_model, arch.spice->spice_models); + } } } /* Connection Boxes */ vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for Connection blocks - X direction ...\n"); /* X - channels [1...nx][0..ny]*/ - for (iy = 0; iy < (ny + 1); iy++) { - for (ix = 1; ix < (nx + 1); ix++) { + for (int iy = 0; iy < (ny + 1); ++iy) { + for (int ix = 1; ix < (nx + 1); ++ix) { /* vpr_printf(TIO_MESSAGE_INFO, "Writing X-direction Connection Boxes[%d][%d]...\n", ix, iy); */ update_spice_models_routing_index_low(ix, iy, CHANX, arch.spice->num_spice_model, arch.spice->spice_models); if ((TRUE == is_cb_exist(CHANX, ix, iy)) &&(0 < count_cb_info_num_ipin_rr_nodes(cbx_info[ix][iy]))) { fpga_spice_generate_bitstream_routing_connection_box_subckt(fp, - &(cbx_info[ix][iy]), cur_sram_orgz_info, - LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + &(cbx_info[ix][iy]), cur_sram_orgz_info); } update_spice_models_routing_index_high(ix, iy, CHANX, arch.spice->num_spice_model, arch.spice->spice_models); } } /* Y - channels [1...ny][0..nx]*/ vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for Connection blocks - Y direction ...\n"); - for (ix = 0; ix < (nx + 1); ix++) { - for (iy = 1; iy < (ny + 1); iy++) { + for (int ix = 0; ix < (nx + 1); ++ix) { + for (int iy = 1; iy < (ny + 1); ++iy) { /* vpr_printf(TIO_MESSAGE_INFO, "Writing Y-direction Connection Boxes[%d][%d]...\n", ix, iy); */ update_spice_models_routing_index_low(ix, iy, CHANY, arch.spice->num_spice_model, arch.spice->spice_models); if ((TRUE == is_cb_exist(CHANY, ix, iy)) &&(0 < count_cb_info_num_ipin_rr_nodes(cby_info[ix][iy]))) { fpga_spice_generate_bitstream_routing_connection_box_subckt(fp, - &(cby_info[ix][iy]), cur_sram_orgz_info, - LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + &(cby_info[ix][iy]), cur_sram_orgz_info); } update_spice_models_routing_index_high(ix, iy, CHANY, arch.spice->num_spice_model, arch.spice->spice_models); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.h b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.h index cd28884e8..f3b86957f 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.h @@ -4,5 +4,4 @@ void fpga_spice_generate_bitstream_routing_resources(char* routing_bitstream_log t_arch arch, t_det_routing_arch* routing_arch, t_sram_orgz_info* cur_sram_orgz_info, - int LL_num_rr_nodes, t_rr_node* LL_rr_node, - t_ivec*** LL_rr_node_indices) ; + boolean compact_routing_hierarchy); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 1d970690b..221706dd4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -395,7 +395,8 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup, verilog_generate_report_timing(sram_verilog_orgz_info, tcl_dir_path, Arch, &vpr_setup.RoutingArch, num_rr_nodes, rr_node, rr_node_indices, - vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts); + vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, + vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy); } if ((TRUE == vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.gen_bitstream) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c index e4d145867..611d2ee4e 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c @@ -846,6 +846,7 @@ void dump_compact_verilog_defined_one_switch_box(t_sram_orgz_info* cur_sram_orgz void dump_compact_verilog_defined_switch_boxes(t_sram_orgz_info* cur_sram_orgz_info, FILE* fp) { DeviceCoordinator sb_range = device_rr_switch_block.get_switch_block_range(); + /* Check the file handler*/ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid file handler.\n", @@ -1140,7 +1141,7 @@ void dump_compact_verilog_defined_one_channel(FILE* fp, /* output at middle point */ for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) { - fprintf(fp, "%s_%d__%d__midout_%u_ ", + fprintf(fp, "%s_%d__%d__midout_%lu_ ", convert_chan_type_to_string(rr_chan.get_type()), x, y, itrack); if (itrack < rr_chan.get_chan_width() - 1) { @@ -1152,7 +1153,7 @@ void dump_compact_verilog_defined_one_channel(FILE* fp, /* Comment lines */ fprintf(fp, - "//----- END Call Verilog Module of %s [%u] -----\n\n", + "//----- END Call Verilog Module of %s [%lu] -----\n\n", convert_chan_type_to_string(rr_chan.get_type()), subckt_id); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.c index f94fe21eb..f017f46ac 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.c @@ -24,6 +24,7 @@ /* Include SPICE support headers*/ #include "linkedlist.h" +#include "rr_blocks.h" #include "fpga_x2p_types.h" #include "fpga_x2p_utils.h" #include "fpga_x2p_backannotate_utils.h" @@ -39,6 +40,8 @@ #include "verilog_routing.h" #include "verilog_tcl_utils.h" +#include "verilog_report_timing.h" + /* options for report timing */ typedef struct s_trpt_opts t_trpt_opts; struct s_trpt_opts { @@ -49,6 +52,7 @@ struct s_trpt_opts { boolean report_sb_timing; boolean report_routing_timing; boolean print_thru_pins; + boolean compact_routing_hierarchy; /* TODO: TO BE DEPRECATED WHEN NEW DATA STRUCTURE HAS BEEN USED */ }; typedef struct s_wireL_cnt t_wireL_cnt; @@ -59,6 +63,7 @@ struct s_wireL_cnt { }; /***** Subroutines *****/ +static char* gen_verilog_one_routing_report_timing_Lwire_dir_path(char* report_timing_path, int L_wire) { char* ret = NULL; @@ -76,6 +81,7 @@ char* gen_verilog_one_routing_report_timing_Lwire_dir_path(char* report_timing_p return ret; } +static char* gen_verilog_one_routing_report_timing_rpt_name(char* report_timing_path, int L_wire, int path_id) { @@ -95,6 +101,7 @@ char* gen_verilog_one_routing_report_timing_rpt_name(char* report_timing_path, return ret; } +static FILE* create_wireL_report_timing_tcl_file_handler(t_trpt_opts trpt_opts, int L_wire) { FILE* fp = NULL; @@ -144,6 +151,7 @@ FILE* create_wireL_report_timing_tcl_file_handler(t_trpt_opts trpt_opts, /* Find a wire length in the linked list, * And return the counter if we found, * Otherwise, we allocate a new member to the linked list */ +static t_llist* get_wire_L_counter_in_llist(t_llist* rr_path_cnt, t_trpt_opts trpt_opts, int L_wire, @@ -178,6 +186,7 @@ t_llist* get_wire_L_counter_in_llist(t_llist* rr_path_cnt, return temp; } +static void fclose_wire_L_file_handler_in_llist(t_llist* rr_path_cnt) { t_llist* temp = rr_path_cnt; t_wireL_cnt* temp_cnt = NULL; @@ -192,6 +201,7 @@ void fclose_wire_L_file_handler_in_llist(t_llist* rr_path_cnt) { return; } +static void update_wire_L_counter_in_llist(t_llist* rr_path_cnt, int L_wire, int path_cnt) { @@ -215,6 +225,7 @@ void update_wire_L_counter_in_llist(t_llist* rr_path_cnt, return; } +static void free_wire_L_llist(t_llist* rr_path_cnt) { t_llist* temp = rr_path_cnt; @@ -232,6 +243,7 @@ void free_wire_L_llist(t_llist* rr_path_cnt) { /* Reporting timing from a SB input to an output */ +static void verilog_generate_one_report_timing_within_sb(FILE* fp, t_sb* cur_sb_info, t_rr_node* src_rr_node, @@ -273,6 +285,7 @@ void verilog_generate_one_report_timing_within_sb(FILE* fp, /* Reporting timing from a SB output to another CB input */ +static void verilog_generate_one_report_timing_sb_to_cb(FILE* fp, t_sb* src_sb_info, t_rr_node* src_rr_node, @@ -314,6 +327,7 @@ void verilog_generate_one_report_timing_sb_to_cb(FILE* fp, /* Reporting timing from a SB output to another SB input */ +static void verilog_generate_one_report_timing_sb_to_sb(FILE* fp, t_sb* src_sb_info, t_rr_node* src_rr_node, @@ -353,7 +367,7 @@ void verilog_generate_one_report_timing_sb_to_sb(FILE* fp, return; } - +static void build_ending_rr_node_for_one_sb_wire(t_rr_node* wire_rr_node, t_rr_node* LL_rr_node, int* num_end_rr_nodes, @@ -454,6 +468,7 @@ void build_ending_rr_node_for_one_sb_wire(t_rr_node* wire_rr_node, * |[x-1][y]| | [x][y]| * -------- -------- */ +static void verilog_generate_report_timing_one_sb_thru_segments(FILE* fp, t_sb* src_sb_info, t_rr_node* src_rr_node, @@ -500,6 +515,7 @@ void verilog_generate_report_timing_one_sb_thru_segments(FILE* fp, * |[x-1][y]| | [x][y]| * -------- ------- */ +static void verilog_generate_report_timing_one_sb_ending_segments(FILE* fp, t_sb* src_sb_info, t_rr_node* src_rr_node, @@ -549,6 +565,7 @@ void verilog_generate_report_timing_one_sb_ending_segments(FILE* fp, /* Print the pins of SBs that a routing wire will go through * from the src_rr_node to the des_rr_node */ +static void dump_verilog_one_sb_wire_segemental_report_timing(FILE* fp, t_syn_verilog_opts fpga_verilog_opts, t_sb* src_sb_info, @@ -791,10 +808,233 @@ void dump_verilog_one_sb_wire_segemental_report_timing(FILE* fp, return; } +/* Print the pins of SBs that a routing wire will go through + * from the src_rr_node to the des_rr_node + */ +static +void dump_verilog_sb_through_routing_pins(FILE* fp, + RRSwitchBlock& src_rr_sb, + t_rr_node* src_rr_node, + t_rr_node* des_rr_node) { + size_t cur_sb_x, cur_sb_y; + size_t end_sb_x, end_sb_y; + t_cb* next_cb; + DeviceCoordinator next_sb_coordinator; + RRSwitchBlock next_sb; + + /* Check the file handler */ + if (NULL == fp) { + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d])Invalid file handler for SDC generation", + __FILE__, __LINE__); + exit(1); + } + + /* Check */ + assert ((INC_DIRECTION == src_rr_node->direction) + ||(DEC_DIRECTION == src_rr_node->direction)); + assert ((CHANX == src_rr_node->type) + ||(CHANY == src_rr_node->type)); + + /* Switch depends on the type of des_rr_node */ + switch(des_rr_node->type) { + /* Range of SBs that on the path + * --------- + * | | + * | des_sb | + * | [x][y] | + * --------- + * /|\ + * | + * --------- + * | | + * | thru_cb | + * | | + * --------- + * /|\ + * | + * -------- ------- --------- ------- -------- + * | | | | | | | | | | + * | des_sb |<---|thru_cb|<---| src_sb |--->|thru_cb|--->| des_sb | + * |[x-1][y]| | [x][y]| | | | [x][y]| |[x][y] | + * -------- ------- --------- ------- -------- + * | + * \|/ + * --------- + * | | + * | thru_cb | + * | | + * --------- + * | + * \|/ + * --------- + * | | + * | des_sb | + * | [x][y-1]| + * --------- + */ + case IPIN: + /* Get the coordinate of ending CB */ + next_cb = get_chan_rr_node_ending_cb(src_rr_node, des_rr_node); + assert(next_cb->type == src_rr_node->type); + /* 4 cases: */ + if ((INC_DIRECTION == src_rr_node->direction) + &&(CHANX == src_rr_node->type)) { + end_sb_x = next_cb->x; + end_sb_y = next_cb->y; + } else if ((INC_DIRECTION == src_rr_node->direction) + &&(CHANY == src_rr_node->type)) { + end_sb_x = next_cb->x; + end_sb_y = next_cb->y; + } else if ((DEC_DIRECTION == src_rr_node->direction) + &&(CHANX == src_rr_node->type)) { + end_sb_x = next_cb->x - 1; + end_sb_y = next_cb->y; + } else if ((DEC_DIRECTION == src_rr_node->direction) + &&(CHANY == src_rr_node->type)) { + end_sb_x = next_cb->x; + end_sb_y = next_cb->y - 1; + } + break; + /* Range of SBs that on the path + * --------- + * | | + * | des_sb | + * | [x][y+1]| + * --------- + * /|\ + * | + * --------- + * | | + * | thru_sb | + * | | + * --------- + * /|\ + * | + * -------- ------- --------- ------- -------- + * | | | | | | | | | | + * | des_sb |<---|thru_sb|<---| src_sb |--->|thru_sb|--->| des_sb | + * |[x-1][y]| | [x][y]| | | | [x][y]| |[x+1][y]| + * -------- ------- --------- ------- -------- + * | + * \|/ + * --------- + * | | + * | thru_sb | + * | | + * --------- + * | + * \|/ + * --------- + * | | + * | des_sb | + * | [x][y-1]| + * --------- + */ + case CHANX: + case CHANY: + /* Get the coordinate of ending CB */ + next_sb_coordinator = get_chan_node_ending_sb_coordinator(src_rr_node, des_rr_node); + next_sb = device_rr_switch_block.get_switch_block(next_sb_coordinator); + end_sb_x = next_sb.get_x(); + end_sb_y = next_sb.get_y(); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, "(File: %s [LINE%d]) Invalid type of rr_node!\n", + __FILE__, __LINE__); + exit(1); + } + + /* Get the base coordinate of src_sb */ + cur_sb_x = src_rr_sb.get_x(); + cur_sb_y = src_rr_sb.get_y(); + /* 4 cases: */ + if ((INC_DIRECTION == src_rr_node->direction) + &&(CHANX == src_rr_node->type)) { + /* Follow the graph above, go through X channel */ + for (size_t ix = src_rr_sb.get_x() + 1; ix < end_sb_x; ++ix) { + /* Print an IN_PORT*/ + fprintf(fp, " "); + /* output instance name */ + DeviceCoordinator inter_sb_coordinator(ix, cur_sb_y); + RRSwitchBlock inter_sb = device_rr_switch_block.get_switch_block(inter_sb_coordinator); + fprintf(fp, "%s/", + inter_sb.gen_verilog_instance_name()); + dump_verilog_one_sb_chan_pin(fp, inter_sb, src_rr_node, IN_PORT); + /* Print an OUT_PORT*/ + fprintf(fp, " "); + /* output instance name */ + fprintf(fp, "%s/", + inter_sb.gen_verilog_instance_name()); + dump_verilog_one_sb_chan_pin(fp, inter_sb, src_rr_node, OUT_PORT); + } + } else if ((INC_DIRECTION == src_rr_node->direction) + &&(CHANY == src_rr_node->type)) { + /* Follow the graph above, go through Y channel */ + for (size_t iy = src_rr_sb.get_y() + 1; iy < end_sb_y; ++iy) { + /* Print an IN_PORT*/ + fprintf(fp, " "); + /* output instance name */ + DeviceCoordinator inter_sb_coordinator(cur_sb_x, iy); + RRSwitchBlock inter_sb = device_rr_switch_block.get_switch_block(inter_sb_coordinator); + fprintf(fp, "%s/", + inter_sb.gen_verilog_instance_name()); + dump_verilog_one_sb_chan_pin(fp, inter_sb, src_rr_node, IN_PORT); + /* Print an OUT_PORT*/ + fprintf(fp, " "); + /* output instance name */ + fprintf(fp, "%s/", + inter_sb.gen_verilog_instance_name()); + dump_verilog_one_sb_chan_pin(fp, inter_sb, src_rr_node, OUT_PORT); + } + } else if ((DEC_DIRECTION == src_rr_node->direction) + &&(CHANX == src_rr_node->type)) { + /* Follow the graph above, go through X channel */ + for (size_t ix = src_rr_sb.get_x() - 1; ix > end_sb_x; --ix) { + /* Print an IN_PORT*/ + fprintf(fp, " "); + /* output instance name */ + DeviceCoordinator inter_sb_coordinator(ix, cur_sb_y); + RRSwitchBlock inter_sb = device_rr_switch_block.get_switch_block(inter_sb_coordinator); + fprintf(fp, "%s/", + inter_sb.gen_verilog_instance_name()); + dump_verilog_one_sb_chan_pin(fp, inter_sb, src_rr_node, IN_PORT); + /* Print an OUT_PORT*/ + fprintf(fp, " "); + /* output instance name */ + fprintf(fp, "%s/", + inter_sb.gen_verilog_instance_name()); + dump_verilog_one_sb_chan_pin(fp, inter_sb, src_rr_node, OUT_PORT); + } + } else if ((DEC_DIRECTION == src_rr_node->direction) + &&(CHANY == src_rr_node->type)) { + /* Follow the graph above, go through Y channel */ + for (size_t iy = src_rr_sb.get_y() - 1; iy > end_sb_y; --iy) { + /* Print an IN_PORT*/ + fprintf(fp, " "); + /* output instance name */ + DeviceCoordinator inter_sb_coordinator(cur_sb_x, iy); + RRSwitchBlock inter_sb = device_rr_switch_block.get_switch_block(inter_sb_coordinator); + fprintf(fp, "%s/", + inter_sb.gen_verilog_instance_name()); + dump_verilog_one_sb_chan_pin(fp, inter_sb, src_rr_node, IN_PORT); + /* Print an OUT_PORT*/ + fprintf(fp, " "); + /* output instance name */ + fprintf(fp, "%s/", + inter_sb.gen_verilog_instance_name()); + dump_verilog_one_sb_chan_pin(fp, inter_sb, src_rr_node, OUT_PORT); + } + } + + return; +} + /* Print the pins of SBs that a routing wire will go through * from the src_rr_node to the des_rr_node */ +static void dump_verilog_sb_through_routing_pins(FILE* fp, t_sb* src_sb_info, t_rr_node* src_rr_node, @@ -1010,13 +1250,162 @@ void dump_verilog_sb_through_routing_pins(FILE* fp, * We check each fan-out to find all possible ending point: * An ending point is supposed to be an OPIN or CHANX or CHANY */ +static +void verilog_generate_one_routing_wire_report_timing(FILE* fp, + t_trpt_opts sdc_opts, + int L_wire, + RRSwitchBlock& rr_sb, + t_rr_node* wire_rr_node, + t_rr_node* LL_rr_node) { + int path_cnt = 0; + + /* Check the file handler */ + if (NULL == fp) { + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d])Invalid file handler for SDC generation", + __FILE__, __LINE__); + exit(1); + } + + assert( ( CHANX == wire_rr_node->type ) + || ( CHANY == wire_rr_node->type )); + int track_idx = wire_rr_node->ptc_num; + + /* We only care a specific length of wires */ + if (L_wire != (abs(wire_rr_node->xlow - wire_rr_node->xhigh + wire_rr_node->ylow - wire_rr_node->yhigh) + 1)) { + return; + } + + /* Find the starting points */ + for (int iedge = 0; iedge < wire_rr_node->num_drive_rr_nodes; iedge++) { + boolean sb_dumped = FALSE; + /* Find the ending points*/ + for (int jedge = 0; jedge < wire_rr_node->num_edges; jedge++) { + int x_end, y_end; + /* Find where the destination pin belongs to */ + get_chan_rr_node_end_coordinate(wire_rr_node, &x_end, &y_end); + DeviceCoordinator next_sb_coordinator; + /* Reciever could be IPIN or CHANX or CHANY */ + int inode = wire_rr_node->edges[jedge]; + RRSwitchBlock next_sb; + t_cb* next_cb = NULL; + /* Find the SB/CB block that it belongs to */ + switch (LL_rr_node[inode].type) { + case IPIN: + /* Get the coordinate of ending CB */ + next_cb = get_chan_rr_node_ending_cb(wire_rr_node, &(LL_rr_node[inode])); + /* This will not be the longest path unless the cb is close to the ending SB */ + if ((TRUE == sdc_opts.longest_path_only) + && ((next_cb->x != x_end) || (next_cb->y != y_end))) { + continue; + } + /* Driver could be OPIN or CHANX or CHANY, + * and it must be in the cur_sb_info + */ + /* Start printing report timing info */ + fprintf(fp, "# L%d wire, Path %d\n", + abs(wire_rr_node->xlow - wire_rr_node->xhigh + wire_rr_node->ylow - wire_rr_node->yhigh) + 1, + path_cnt); + fprintf(fp, "report_timing -from "); + /* output instance name */ + fprintf(fp, "%s/", rr_sb.gen_verilog_instance_name()); + /* output pin name */ + dump_verilog_one_sb_routing_pin(fp, rr_sb, + wire_rr_node->drive_rr_nodes[iedge]); + fprintf(fp, " -to "); + /* output instance name */ + fprintf(fp, "%s/", + gen_verilog_one_cb_instance_name(next_cb)); + /* output pin name */ + fprintf(fp, "%s", + gen_verilog_routing_channel_one_midout_name( next_cb, + track_idx)); + /* Print through pins */ + if (TRUE == sdc_opts.print_thru_pins) { + fprintf(fp, " -through_pins "); + dump_verilog_sb_through_routing_pins(fp, rr_sb, wire_rr_node, &(LL_rr_node[inode])); + } else { + fprintf(fp, " -point_to_point\n"); + } + fprintf(fp, " -unconstrained\n"); + path_cnt++; + break; + case CHANX: + case CHANY: + /* Get the coordinate of ending SB */ + next_sb_coordinator = get_chan_node_ending_sb_coordinator(wire_rr_node, &(LL_rr_node[inode])); + next_sb = device_rr_switch_block.get_switch_block(next_sb_coordinator); + /* This will not be the longest path unless the cb is close to the ending SB */ + if ((TRUE == sdc_opts.longest_path_only) + && ((next_sb.get_x() != (size_t)x_end) || (next_sb.get_y() != (size_t)y_end))) { + continue; + } + if (TRUE == sb_dumped) { + continue; + } + /* Driver could be OPIN or CHANX or CHANY, + * and it must be in the cur_sb_info + */ + /* Start printing report timing info */ + fprintf(fp, "# L%d wire, Path %d\n", + abs(wire_rr_node->xlow - wire_rr_node->xhigh + wire_rr_node->ylow - wire_rr_node->yhigh) + 1, + path_cnt); + fprintf(fp, "report_timing -from "); + /* output instance name */ + fprintf(fp, "%s/", + rr_sb.gen_verilog_instance_name()); + /* output pin name */ + dump_verilog_one_sb_routing_pin(fp, rr_sb, + wire_rr_node->drive_rr_nodes[iedge]); + fprintf(fp, " -to "); + /* output instance name */ + fprintf(fp, "%s/", + next_sb.gen_verilog_instance_name()); + /* Find which side the ending pin locates, and determine the coordinate */ + dump_verilog_one_sb_routing_pin(fp, next_sb, + wire_rr_node); + /* Print through pins */ + if (TRUE == sdc_opts.print_thru_pins) { + fprintf(fp, " -through_pins "); + dump_verilog_sb_through_routing_pins(fp, rr_sb, + wire_rr_node, &(LL_rr_node[inode])); + } else { + fprintf(fp, " -point_to_point\n"); + } + fprintf(fp, " -unconstrained\n"); + path_cnt++; + /* Set the flag */ + sb_dumped = TRUE; + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, "(File: %s [LINE%d]) Invalid type of ending point rr_node!\n", + __FILE__, __LINE__); + + exit(1); + } + /* Get the user-constrained delay of this routing wire */ + /* Find the pins/ports of SBs that this wire may across */ + /* Output the Report Timing commands */ + } + } + + return; +} + + +/* Report timing for a routing wire, + * Support uni-directional routing architecture + * Each routing wire start from an OPIN + * We check each fan-out to find all possible ending point: + * An ending point is supposed to be an OPIN or CHANX or CHANY + */ +static void verilog_generate_one_routing_wire_report_timing(FILE* fp, t_trpt_opts sdc_opts, int L_wire, t_sb* cur_sb_info, t_rr_node* wire_rr_node, - int LL_num_rr_nodes, t_rr_node* LL_rr_node, - t_ivec*** LL_rr_node_indices) { + t_rr_node* LL_rr_node) { int iedge, jedge, inode; int track_idx; int path_cnt = 0; @@ -1155,15 +1544,11 @@ void verilog_generate_one_routing_wire_report_timing(FILE* fp, } /* Generate report timing for each routing wires/segments */ +static void verilog_generate_routing_wires_report_timing(FILE* fp, t_trpt_opts sdc_opts, int L_wire, - int LL_num_rr_nodes, t_rr_node* LL_rr_node, - t_ivec*** LL_rr_node_indices) { - int ix, iy; - int side, itrack; - t_sb* cur_sb_info = NULL; - + t_rr_node* LL_rr_node) { /* Check the file handler */ if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR, @@ -1172,42 +1557,70 @@ void verilog_generate_routing_wires_report_timing(FILE* fp, exit(1); } - /* We start from a SB[x][y] */ - for (ix = 0; ix < (nx + 1); ix++) { - for (iy = 0; iy < (ny + 1); iy++) { - cur_sb_info = &(sb_info[ix][iy]); - for (side = 0; side < cur_sb_info->num_sides; side++) { - for (itrack = 0; itrack < cur_sb_info->chan_width[side]; itrack++) { - assert((CHANX == cur_sb_info->chan_rr_node[side][itrack]->type) - ||(CHANY == cur_sb_info->chan_rr_node[side][itrack]->type)); - /* We only care the output port and it should indicate a SB mux */ - if ( (OUT_PORT != cur_sb_info->chan_rr_node_direction[side][itrack]) - || (FALSE != check_drive_rr_node_imply_short(*cur_sb_info, cur_sb_info->chan_rr_node[side][itrack], side))) { - continue; + if (TRUE == sdc_opts.compact_routing_hierarchy) { + DeviceCoordinator sb_range = device_rr_switch_block.get_switch_block_range(); + for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { + RRSwitchBlock rr_sb = device_rr_switch_block.get_switch_block(ix, iy); + for (size_t side = 0; side < rr_sb.get_num_sides(); side++) { + Side side_manager(side); + for (size_t itrack = 0; itrack < rr_sb.get_chan_width(side_manager.get_side()); ++itrack) { + assert((CHANX == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type) + ||(CHANY == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type)); + /* We only care the output port and it should indicate a SB mux */ + if ( (OUT_PORT != rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) + || (true == rr_sb.is_node_imply_short_connection(rr_sb.get_chan_node(side_manager.get_side(), itrack)))) { + continue; + } + /* Bypass if we have only 1 driving node */ + if (1 == rr_sb.get_chan_node(side_manager.get_side(), itrack)->num_drive_rr_nodes) { + continue; + } + /* Reach here, it means a valid starting point of a routing wire */ + verilog_generate_one_routing_wire_report_timing(fp, sdc_opts, L_wire, rr_sb, + rr_sb.get_chan_node(side_manager.get_side(), itrack), + LL_rr_node); + } - /* Bypass if we have only 1 driving node */ - if (1 == cur_sb_info->chan_rr_node[side][itrack]->num_drive_rr_nodes) { - continue; - } - /* Reach here, it means a valid starting point of a routing wire */ - verilog_generate_one_routing_wire_report_timing(fp, sdc_opts, L_wire, &(sb_info[ix][iy]), - cur_sb_info->chan_rr_node[side][itrack], - LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); } - } + } + } + } else { + t_sb* cur_sb_info = NULL; + /* We start from a SB[x][y] */ + for (int ix = 0; ix < (nx + 1); ix++) { + for (int iy = 0; iy < (ny + 1); iy++) { + cur_sb_info = &(sb_info[ix][iy]); + for (int side = 0; side < cur_sb_info->num_sides; side++) { + for (int itrack = 0; itrack < cur_sb_info->chan_width[side]; itrack++) { + assert((CHANX == cur_sb_info->chan_rr_node[side][itrack]->type) + ||(CHANY == cur_sb_info->chan_rr_node[side][itrack]->type)); + /* We only care the output port and it should indicate a SB mux */ + if ( (OUT_PORT != cur_sb_info->chan_rr_node_direction[side][itrack]) + || (FALSE != check_drive_rr_node_imply_short(*cur_sb_info, cur_sb_info->chan_rr_node[side][itrack], side))) { + continue; + } + /* Bypass if we have only 1 driving node */ + if (1 == cur_sb_info->chan_rr_node[side][itrack]->num_drive_rr_nodes) { + continue; + } + /* Reach here, it means a valid starting point of a routing wire */ + verilog_generate_one_routing_wire_report_timing(fp, sdc_opts, L_wire, &(sb_info[ix][iy]), + cur_sb_info->chan_rr_node[side][itrack], + LL_rr_node); + } + } + } } } return; } -void verilog_generate_sb_report_timing(t_sram_orgz_info* cur_sram_orgz_info, - t_trpt_opts sdc_opts, +static +void verilog_generate_sb_report_timing(t_trpt_opts sdc_opts, t_arch arch, - t_det_routing_arch* routing_arch, - int LL_num_rr_nodes, t_rr_node* LL_rr_node, - t_ivec*** LL_rr_node_indices, - t_syn_verilog_opts fpga_verilog_opts) { + t_rr_node* LL_rr_node) { char* sdc_fname = NULL; FILE* fp = NULL; int iseg; @@ -1249,12 +1662,12 @@ void verilog_generate_sb_report_timing(t_sram_orgz_info* cur_sram_orgz_info, if ((L_max > nx) && (L_max > ny)) { if (nx != ny) { verilog_generate_routing_wires_report_timing(fp, sdc_opts, - nx, LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + nx, LL_rr_node); verilog_generate_routing_wires_report_timing(fp, sdc_opts, - ny, LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + ny, LL_rr_node); } else { verilog_generate_routing_wires_report_timing(fp, sdc_opts, - nx, LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + nx, LL_rr_node); } } else { /* We only care defined length of wires? */ @@ -1264,7 +1677,7 @@ void verilog_generate_sb_report_timing(t_sram_orgz_info* cur_sram_orgz_info, continue; } verilog_generate_routing_wires_report_timing(fp, sdc_opts, arch.Segments[iseg].length, - LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + LL_rr_node); } } @@ -1282,12 +1695,12 @@ void verilog_generate_sb_report_timing(t_sram_orgz_info* cur_sram_orgz_info, * We consider the farest ending point and report timing for each segements on the path * We output TCL commands to sum up the segmental delay */ +static void verilog_generate_one_routing_segmental_report_timing(FILE* fp, t_syn_verilog_opts fpga_verilog_opts, t_sb* cur_sb_info, t_rr_node* wire_rr_node, - int LL_num_rr_nodes, t_rr_node* LL_rr_node, - t_ivec*** LL_rr_node_indices, + t_rr_node* LL_rr_node, int* path_cnt) { int iedge, jedge; int num_end_rr_nodes = 0; @@ -1330,12 +1743,9 @@ void verilog_generate_one_routing_segmental_report_timing(FILE* fp, return; } -void verilog_generate_routing_report_timing(t_sram_orgz_info* cur_sram_orgz_info, - t_trpt_opts trpt_opts, - t_arch arch, - t_det_routing_arch* routing_arch, - int LL_num_rr_nodes, t_rr_node* LL_rr_node, - t_ivec*** LL_rr_node_indices, +static +void verilog_generate_routing_report_timing(t_trpt_opts trpt_opts, + t_rr_node* LL_rr_node, t_syn_verilog_opts fpga_verilog_opts) { FILE* fp = NULL; int ix, iy; @@ -1387,8 +1797,7 @@ void verilog_generate_routing_report_timing(t_sram_orgz_info* cur_sram_orgz_info verilog_generate_one_routing_segmental_report_timing(fp, fpga_verilog_opts, cur_sb_info, cur_sb_info->chan_rr_node[side][itrack], - LL_num_rr_nodes, LL_rr_node, - LL_rr_node_indices, &path_cnt); + LL_rr_node, &path_cnt); /* Disable the timing again */ fprintf(fp, "# Set disable timing for the following Switch Block output:\n"); set_disable_timing_one_sb_output(fp, @@ -1417,7 +1826,8 @@ void verilog_generate_report_timing(t_sram_orgz_info* cur_sram_orgz_info, t_det_routing_arch* routing_arch, int LL_num_rr_nodes, t_rr_node* LL_rr_node, t_ivec*** LL_rr_node_indices, - t_syn_verilog_opts fpga_verilog_opts) { + t_syn_verilog_opts fpga_verilog_opts, + boolean compact_routing_hierarchy) { t_trpt_opts trpt_opts; /* Initialize */ @@ -1428,6 +1838,7 @@ void verilog_generate_report_timing(t_sram_orgz_info* cur_sram_orgz_info, trpt_opts.longest_path_only = TRUE; trpt_opts.print_thru_pins = TRUE; trpt_opts.sdc_dir = my_strdup(sdc_dir); + trpt_opts.compact_routing_hierarchy = compact_routing_hierarchy; /* Part 1. Report timing for Programmable Logic Blocks */ @@ -1435,17 +1846,13 @@ void verilog_generate_report_timing(t_sram_orgz_info* cur_sram_orgz_info, /* Part 3. Report timing for Switch Blocks */ if (TRUE == trpt_opts.report_sb_timing) { - verilog_generate_sb_report_timing(cur_sram_orgz_info, trpt_opts, - arch, routing_arch, - LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices, - fpga_verilog_opts); + verilog_generate_sb_report_timing(trpt_opts, arch, LL_rr_node); } /* Part 3. Report timing for routing segments of SB wires */ if (TRUE == trpt_opts.report_routing_timing) { - verilog_generate_routing_report_timing(cur_sram_orgz_info, trpt_opts, - arch, routing_arch, - LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices, + verilog_generate_routing_report_timing(trpt_opts, + LL_rr_node, fpga_verilog_opts); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.h index 97c7a1b1d..655ed91ff 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.h @@ -5,5 +5,6 @@ void verilog_generate_report_timing(t_sram_orgz_info* cur_sram_orgz_info, t_det_routing_arch* routing_arch, int LL_num_rr_nodes, t_rr_node* LL_rr_node, t_ivec*** LL_rr_node_indices, - t_syn_verilog_opts fpga_verilog_opts); + t_syn_verilog_opts fpga_verilog_opts, + boolean compact_routing_hierarchy); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.c index 0acd728ed..61eccfad2 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.c @@ -37,6 +37,8 @@ #include "verilog_utils.h" #include "verilog_routing.h" +#include "verilog_tcl_utils.h" + /***** Subroutine Functions *****/ void dump_verilog_sdc_file_header(FILE* fp, char* usage) { @@ -57,6 +59,39 @@ void dump_verilog_sdc_file_header(FILE* fp, return; } +void dump_verilog_one_sb_chan_pin(FILE* fp, + RRSwitchBlock& rr_sb, + t_rr_node* cur_rr_node, + enum PORTS port_type) { + int track_idx; + enum e_side side; + int x_start, y_start; + char* pin_name; + + /* Check the file handler */ + if (NULL == fp) { + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d])Invalid file handler for SDC generation", + __FILE__, __LINE__); + exit(1); + } + + /* Check */ + assert ((CHANX == cur_rr_node->type) + ||(CHANY == cur_rr_node->type)); + /* Get the coordinate of chanx or chany*/ + /* Find the coordinate of the cur_rr_node */ + rr_sb.get_node_side_and_index(cur_rr_node, port_type, &side, &track_idx); + /* Print the pin of the cur_rr_node */ + pin_name = gen_verilog_routing_channel_one_pin_name(cur_rr_node, + x_start, y_start, track_idx, + port_type); + fprintf(fp, "%s", pin_name); + my_free(pin_name); + + return; +} + void dump_verilog_one_sb_chan_pin(FILE* fp, t_sb* cur_sb_info, @@ -96,6 +131,48 @@ void dump_verilog_one_sb_chan_pin(FILE* fp, return; } +/* Output the pin name of a routing wire in a SB */ +void dump_verilog_one_sb_routing_pin(FILE* fp, + RRSwitchBlock& rr_sb, + t_rr_node* cur_rr_node) { + int side; + + /* Check the file handler */ + if (NULL == fp) { + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d])Invalid file handler for SDC generation", + __FILE__, __LINE__); + exit(1); + } + + /* Get the top-level pin name and print it out */ + /* Depends on the type of node */ + switch (cur_rr_node->type) { + case OPIN: + /* Identify the side of OPIN on a grid */ + side = get_grid_pin_side(cur_rr_node->xlow, cur_rr_node->ylow, cur_rr_node->ptc_num); + assert (OPEN != side); + dump_verilog_grid_side_pin_with_given_index(fp, OPIN, + cur_rr_node->ptc_num, + side, + cur_rr_node->xlow, + cur_rr_node->ylow, + FALSE); /* Do not specify direction of port */ + break; + case CHANX: + case CHANY: + dump_verilog_one_sb_chan_pin(fp, rr_sb, cur_rr_node, IN_PORT); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, "(File: %s [LINE%d]) Invalid type of ending point rr_node!\n", + __FILE__, __LINE__); + + exit(1); + } + + return; +} + /* Output the pin name of a routing wire in a SB */ void dump_verilog_one_sb_routing_pin(FILE* fp, t_sb* cur_sb_info, @@ -217,6 +294,126 @@ t_cb* get_chan_rr_node_ending_cb(t_rr_node* src_rr_node, return next_cb; } +/** Given a starting rr_node (CHANX or CHANY) + * and a ending rr_node (IPIN) + * return the sb contains both (the ending CB of the routing wire) + */ +DeviceCoordinator get_chan_node_ending_sb_coordinator(t_rr_node* src_rr_node, + t_rr_node* end_rr_node) { + int x_start, y_start; + int x_end, y_end; + int next_sb_x, next_sb_y; + + get_chan_rr_node_start_coordinate(src_rr_node, &x_start, &y_start); + get_chan_rr_node_start_coordinate(end_rr_node, &x_end, &y_end); + + /* Case 1: + * end_rr_node(chany[x][y+1]) + * /|\ + * | + * --------- + * | | + * src_rr_node ------>| next_sb |-------> end_rr_node + * (chanx[x][y]) | [x][y] | (chanx[x+1][y] + * --------- + * | + * \|/ + * end_rr_node(chany[x][y]) + */ + /* Case 2 + * end_rr_node(chany[x][y+1]) + * /|\ + * | + * --------- + * | | + * end_rr_node <------| next_sb |<-------- src_rr_node + * (chanx[x][y]) | [x][y] | (chanx[x+1][y] + * --------- + * | + * \|/ + * end_rr_node(chany[x][y]) + */ + /* Case 3 + * end_rr_node(chany[x][y+1]) + * /|\ + * | + * --------- + * | | + * end_rr_node <------| next_sb |-------> src_rr_node + * (chanx[x][y]) | [x][y] | (chanx[x+1][y] + * --------- + * /|\ + * | + * src_rr_node(chany[x][y]) + */ + /* Case 4 + * src_rr_node(chany[x][y+1]) + * | + * \|/ + * --------- + * | | + * end_rr_node <------| next_sb |--------> end_rr_node + * (chanx[x][y]) | [x][y] | (chanx[x+1][y] + * --------- + * | + * \|/ + * end_rr_node(chany[x][y]) + */ + + + /* Try the xlow, ylow of ending rr_node */ + switch (src_rr_node->type) { + case CHANX: + next_sb_x = x_end; + next_sb_y = y_start; + break; + case CHANY: + next_sb_x = x_start; + next_sb_y = y_end; + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, "(File: %s [LINE%d]) Invalid type of rr_node!\n", + __FILE__, __LINE__); + exit(1); + } + + switch (src_rr_node->direction) { + case INC_DIRECTION: + get_chan_rr_node_end_coordinate(src_rr_node, &x_end, &y_end); + if (next_sb_x > x_end) { + next_sb_x = x_end; + } + if (next_sb_y > y_end) { + next_sb_y = y_end; + } + break; + case DEC_DIRECTION: + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, "(File: %s [LINE%d]) Invalid type of rr_node!\n", + __FILE__, __LINE__); + exit(1); + } + + DeviceCoordinator sb_coordinator(next_sb_x, next_sb_y); + RRSwitchBlock rr_sb = device_rr_switch_block.get_switch_block(sb_coordinator); + /* Double check if src_rr_node is in the list */ + enum e_side side; + int index; + rr_sb.get_node_side_and_index(src_rr_node, IN_PORT, &side, &index); + assert ( (OPEN != index) && (side != NUM_SIDES) ); + + /* Double check if end_rr_node is in the list */ + rr_sb.get_node_side_and_index(end_rr_node, OUT_PORT, &side, &index); + assert ( (OPEN != index) && (side != NUM_SIDES) ); + + /* Passing the check, assign coordinator of next_sb */ + + return sb_coordinator; + +} + + /** Given a starting rr_node (CHANX or CHANY) * and a ending rr_node (IPIN) * return the sb contains both (the ending CB of the routing wire) @@ -351,6 +548,32 @@ t_sb* get_chan_rr_node_ending_sb(t_rr_node* src_rr_node, return next_sb; } +/* Restore the disabled timing for the sb wire */ +void restore_disable_timing_one_sb_output(FILE* fp, + RRSwitchBlock& rr_sb, + t_rr_node* wire_rr_node) { + /* Check the file handler */ + if (NULL == fp) { + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d])Invalid file handler for SDC generation", + __FILE__, __LINE__); + exit(1); + } + + assert( ( CHANX == wire_rr_node->type ) + || ( CHANY == wire_rr_node->type )); + + /* Restore disabled timing for wire_rr_node as an SB output */ + fprintf(fp, "reset_disable_timing "); + /* output instance name */ + fprintf(fp, "%s/", + rr_sb.gen_verilog_instance_name()); + dump_verilog_one_sb_chan_pin(fp, rr_sb, wire_rr_node, OUT_PORT); + fprintf(fp, "\n"); + + return; +} + /* Restore the disabled timing for the sb wire */ void restore_disable_timing_one_sb_output(FILE* fp, t_sb* cur_sb_info, @@ -377,6 +600,32 @@ void restore_disable_timing_one_sb_output(FILE* fp, return; } +/* Restore the disabled timing for the sb wire */ +void set_disable_timing_one_sb_output(FILE* fp, + RRSwitchBlock& rr_sb, + t_rr_node* wire_rr_node) { + /* Check the file handler */ + if (NULL == fp) { + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d])Invalid file handler for SDC generation", + __FILE__, __LINE__); + exit(1); + } + + assert( ( CHANX == wire_rr_node->type ) + || ( CHANY == wire_rr_node->type )); + + /* Restore disabled timing for wire_rr_node as an SB output */ + fprintf(fp, "set_disable_timing "); + /* output instance name */ + fprintf(fp, "%s/", + rr_sb.gen_verilog_instance_name()); + dump_verilog_one_sb_chan_pin(fp, rr_sb, wire_rr_node, OUT_PORT); + fprintf(fp, "\n"); + + return; +} + /* Restore the disabled timing for the sb wire */ void set_disable_timing_one_sb_output(FILE* fp, t_sb* cur_sb_info, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.h index 2a44f1ab2..cab307677 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.h @@ -1,12 +1,27 @@ +#ifndef VERILOG_TCL_UTILS_H +#define VERILOG_TCL_UTILS_H + +/* Include header files that require by the function declared in the following lines !!!*/ +#include "device_coordinator.h" +#include "rr_blocks.h" void dump_verilog_sdc_file_header(FILE* fp, char* usage); +void dump_verilog_one_sb_chan_pin(FILE* fp, + RRSwitchBlock& rr_sb, + t_rr_node* cur_rr_node, + enum PORTS port_type); + void dump_verilog_one_sb_chan_pin(FILE* fp, t_sb* cur_sb_info, t_rr_node* cur_rr_node, enum PORTS port_type); +void dump_verilog_one_sb_routing_pin(FILE* fp, + RRSwitchBlock& rr_sb, + t_rr_node* cur_rr_node); + void dump_verilog_one_sb_routing_pin(FILE* fp, t_sb* cur_sb_info, t_rr_node* cur_rr_node); @@ -14,13 +29,26 @@ void dump_verilog_one_sb_routing_pin(FILE* fp, t_cb* get_chan_rr_node_ending_cb(t_rr_node* src_rr_node, t_rr_node* end_rr_node); +DeviceCoordinator get_chan_node_ending_sb_coordinator(t_rr_node* src_rr_node, + t_rr_node* end_rr_node); + t_sb* get_chan_rr_node_ending_sb(t_rr_node* src_rr_node, t_rr_node* end_rr_node); +void restore_disable_timing_one_sb_output(FILE* fp, + RRSwitchBlock& rr_sb, + t_rr_node* wire_rr_node); + void restore_disable_timing_one_sb_output(FILE* fp, t_sb* cur_sb_info, t_rr_node* wire_rr_node); +void set_disable_timing_one_sb_output(FILE* fp, + RRSwitchBlock& rr_sb, + t_rr_node* wire_rr_node); + void set_disable_timing_one_sb_output(FILE* fp, t_sb* cur_sb_info, t_rr_node* wire_rr_node); + +#endif