updated bitstream to use new RRSwitchBlock as well as the report timing engine

This commit is contained in:
tangxifan 2019-05-24 12:54:10 -06:00
parent 5de38f023c
commit eef1312325
12 changed files with 995 additions and 158 deletions

View File

@ -0,0 +1,6 @@
#ifndef MY_FREE_FWD_H
#define MY_FREE_FWD_H
void my_free(void* ptr);
#endif

View File

@ -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

View File

@ -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();

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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,

View File

@ -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