refactoring SDC generator for unused CBs
This commit is contained in:
parent
67b3b25bea
commit
3d711823e5
|
@ -0,0 +1,240 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes functions that are used to output a SDC file
|
||||||
|
* that constrain routing modules of a FPGA fabric (P&Red netlist)
|
||||||
|
* using a benchmark
|
||||||
|
*******************************************************************/
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "device_port.h"
|
||||||
|
|
||||||
|
#include "fpga_x2p_naming.h"
|
||||||
|
#include "fpga_x2p_utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "sdc_writer_utils.h"
|
||||||
|
#include "analysis_sdc_routing_writer.h"
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Identify if a node should be disabled during analysis SDC generation
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node) {
|
||||||
|
/* Conditions to enable timing analysis for a node
|
||||||
|
* 1st condition: it have a valid vpack_net_number
|
||||||
|
* 2nd condition: it is not an parasitic net
|
||||||
|
* 3rd condition: it is not a global net
|
||||||
|
*/
|
||||||
|
if ( (OPEN != cur_rr_node->vpack_net_num)
|
||||||
|
&& (FALSE == cur_rr_node->is_parasitic_net)
|
||||||
|
&& (FALSE == vpack_net[cur_rr_node->vpack_net_num].is_global)
|
||||||
|
&& (FALSE == vpack_net[cur_rr_node->vpack_net_num].is_const_gen) ){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will disable
|
||||||
|
* 1. all the unused port (unmapped by a benchmark) of a connection block
|
||||||
|
* 2. all the unused inputs (unmapped by a benchmark) of routing multiplexers
|
||||||
|
* in a connection block
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const DeviceRRGSB& L_device_rr_gsb,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const RRGSB& rr_gsb,
|
||||||
|
const t_rr_type& cb_type,
|
||||||
|
const bool& compact_routing_hierarchy) {
|
||||||
|
/* Validate file stream */
|
||||||
|
check_file_handler(fp);
|
||||||
|
|
||||||
|
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||||
|
|
||||||
|
std::string cb_instance_name = generate_connection_block_module_name(cb_type, gsb_coordinate);
|
||||||
|
|
||||||
|
/* If we use the compact routing hierarchy, we need to find the module name !*/
|
||||||
|
vtr::Point<size_t> cb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||||
|
if (true == compact_routing_hierarchy) {
|
||||||
|
DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||||
|
/* Note: use GSB coordinate when inquire for unique modules!!! */
|
||||||
|
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
|
||||||
|
cb_coordinate.set_x(unique_mirror.get_cb_x(cb_type));
|
||||||
|
cb_coordinate.set_y(unique_mirror.get_cb_y(cb_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cb_module_name = generate_connection_block_module_name(cb_type, cb_coordinate);
|
||||||
|
|
||||||
|
ModuleId cb_module = module_manager.find_module(cb_module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(cb_module));
|
||||||
|
|
||||||
|
/* Print comments */
|
||||||
|
fp << "##################################################" << std::endl;
|
||||||
|
fp << "# Disable timing for Connection block " << cb_module_name << std::endl;
|
||||||
|
fp << "##################################################" << std::endl;
|
||||||
|
|
||||||
|
/* Disable all the input port (routing tracks), which are not used by benchmark */
|
||||||
|
for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) {
|
||||||
|
t_rr_node* chan_node = rr_gsb.get_chan_node(rr_gsb.get_cb_chan_side(cb_type), itrack);
|
||||||
|
/* Check if this node is used by benchmark */
|
||||||
|
if (false == is_rr_node_to_be_disable_for_analysis(chan_node)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable both input of the routing track if it is not used! */
|
||||||
|
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||||
|
if (true == compact_routing_hierarchy) {
|
||||||
|
/* Note: use GSB coordinate when inquire for unique modules!!! */
|
||||||
|
DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||||
|
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
|
||||||
|
port_coord.set_x(unique_mirror.get_cb_x(cb_type));
|
||||||
|
port_coord.set_y(unique_mirror.get_cb_y(cb_type));
|
||||||
|
}
|
||||||
|
std::string port_name = generate_routing_track_port_name(cb_type,
|
||||||
|
port_coord, itrack,
|
||||||
|
IN_PORT);
|
||||||
|
|
||||||
|
/* Ensure we have this port in the module! */
|
||||||
|
ModulePortId module_port = module_manager.find_module_port(cb_module, port_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port));
|
||||||
|
|
||||||
|
fp << "set_disable_timing ";
|
||||||
|
fp << cb_instance_name << "/";
|
||||||
|
fp << generate_sdc_port(module_manager.module_port(cb_module, module_port));
|
||||||
|
fp << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable all the output port (routing tracks), which are not used by benchmark */
|
||||||
|
for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) {
|
||||||
|
t_rr_node* chan_node = rr_gsb.get_chan_node(rr_gsb.get_cb_chan_side(cb_type), itrack);
|
||||||
|
/* Check if this node is used by benchmark */
|
||||||
|
if (false == is_rr_node_to_be_disable_for_analysis(chan_node)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable both input of the routing track if it is not used! */
|
||||||
|
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||||
|
if (true == compact_routing_hierarchy) {
|
||||||
|
/* Note: use GSB coordinate when inquire for unique modules!!! */
|
||||||
|
DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||||
|
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
|
||||||
|
port_coord.set_x(unique_mirror.get_cb_x(cb_type));
|
||||||
|
port_coord.set_y(unique_mirror.get_cb_y(cb_type));
|
||||||
|
}
|
||||||
|
std::string port_name = generate_routing_track_port_name(cb_type,
|
||||||
|
port_coord, itrack,
|
||||||
|
OUT_PORT);
|
||||||
|
|
||||||
|
/* Ensure we have this port in the module! */
|
||||||
|
ModulePortId module_port = module_manager.find_module_port(cb_module, port_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port));
|
||||||
|
|
||||||
|
fp << "set_disable_timing ";
|
||||||
|
fp << cb_instance_name << "/";
|
||||||
|
fp << generate_sdc_port(module_manager.module_port(cb_module, module_port));
|
||||||
|
fp << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable all the output port (grid input pins), which are not used by benchmark */
|
||||||
|
std::vector<enum e_side> cb_sides = rr_gsb.get_cb_ipin_sides(cb_type);
|
||||||
|
|
||||||
|
for (size_t side = 0; side < cb_sides.size(); ++side) {
|
||||||
|
enum e_side cb_ipin_side = cb_sides[side];
|
||||||
|
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) {
|
||||||
|
t_rr_node* ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode);
|
||||||
|
if (false == is_rr_node_to_be_disable_for_analysis(ipin_node)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (0 == ipin_node->fan_in) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vtr::Point<size_t> port_coord(ipin_node->xlow, ipin_node->ylow);
|
||||||
|
std::string port_name = generate_grid_side_port_name(grids,
|
||||||
|
port_coord,
|
||||||
|
rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode),
|
||||||
|
ipin_node->ptc_num);
|
||||||
|
|
||||||
|
/* Find the port in unique mirror! */
|
||||||
|
if (true == compact_routing_hierarchy) {
|
||||||
|
/* Note: use GSB coordinate when inquire for unique modules!!! */
|
||||||
|
DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y());
|
||||||
|
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
|
||||||
|
t_rr_node* unique_mirror_ipin_node = unique_mirror.get_ipin_node(cb_ipin_side, inode);
|
||||||
|
port_coord.set_x(unique_mirror_ipin_node->xlow);
|
||||||
|
port_coord.set_y(unique_mirror_ipin_node->ylow);
|
||||||
|
port_name = generate_grid_side_port_name(grids,
|
||||||
|
port_coord,
|
||||||
|
unique_mirror.get_ipin_node_grid_side(cb_ipin_side, inode),
|
||||||
|
unique_mirror_ipin_node->ptc_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure we have this port in the module! */
|
||||||
|
ModulePortId module_port = module_manager.find_module_port(cb_module, port_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port));
|
||||||
|
|
||||||
|
fp << "set_disable_timing ";
|
||||||
|
fp << cb_instance_name << "/";
|
||||||
|
fp << generate_sdc_port(module_manager.module_port(cb_module, module_port));
|
||||||
|
fp << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Disable all the unused inputs of routing multiplexers, which are not used by benchmark */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Iterate over all the connection blocks in a device
|
||||||
|
* and disable unused ports for each of them
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const DeviceRRGSB& L_device_rr_gsb,
|
||||||
|
const t_rr_type& cb_type,
|
||||||
|
const bool& compact_routing_hierarchy) {
|
||||||
|
/* Build unique X-direction connection block modules */
|
||||||
|
DeviceCoordinator cb_range = L_device_rr_gsb.get_gsb_range();
|
||||||
|
|
||||||
|
for (size_t ix = 0; ix < cb_range.get_x(); ++ix) {
|
||||||
|
for (size_t iy = 0; iy < cb_range.get_y(); ++iy) {
|
||||||
|
/* Check if the connection block exists in the device!
|
||||||
|
* Some of them do NOT exist due to heterogeneous blocks (height > 1)
|
||||||
|
* We will skip those modules
|
||||||
|
*/
|
||||||
|
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy);
|
||||||
|
if (false == rr_gsb.is_cb_exist(cb_type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_analysis_sdc_disable_cb_unused_resources(fp, grids, L_device_rr_gsb,
|
||||||
|
module_manager,
|
||||||
|
rr_gsb,
|
||||||
|
cb_type,
|
||||||
|
compact_routing_hierarchy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Iterate over all the connection blocks in a device
|
||||||
|
* and disable unused ports for each of them
|
||||||
|
*******************************************************************/
|
||||||
|
void print_analysis_sdc_disable_unused_cbs(std::fstream& fp,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const DeviceRRGSB& L_device_rr_gsb,
|
||||||
|
const bool& compact_routing_hierarchy) {
|
||||||
|
|
||||||
|
print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager,
|
||||||
|
L_device_rr_gsb,
|
||||||
|
CHANX, compact_routing_hierarchy);
|
||||||
|
|
||||||
|
print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager,
|
||||||
|
L_device_rr_gsb,
|
||||||
|
CHANY, compact_routing_hierarchy);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef ANALYSIS_SDC_ROUTING_WRITER_H
|
||||||
|
#define ANALYSIS_SDC_ROUTING_WRITER_H
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
#include "module_manager.h"
|
||||||
|
#include "rr_blocks.h"
|
||||||
|
#include "vpr_types.h"
|
||||||
|
|
||||||
|
void print_analysis_sdc_disable_unused_cbs(std::fstream& fp,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const DeviceRRGSB& L_device_rr_gsb,
|
||||||
|
const bool& compact_routing_hierarchy);
|
||||||
|
#endif
|
|
@ -20,6 +20,7 @@
|
||||||
#include "sdc_writer_utils.h"
|
#include "sdc_writer_utils.h"
|
||||||
#include "sdc_memory_utils.h"
|
#include "sdc_memory_utils.h"
|
||||||
|
|
||||||
|
#include "analysis_sdc_routing_writer.h"
|
||||||
#include "analysis_sdc_writer.h"
|
#include "analysis_sdc_writer.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -241,20 +242,12 @@ void print_analysis_sdc(const std::string& sdc_dir,
|
||||||
format_dir_path(module_manager.module_name(top_module)));
|
format_dir_path(module_manager.module_name(top_module)));
|
||||||
|
|
||||||
|
|
||||||
/* TODO: Disable timing for un-used resources */
|
/* TODO: Disable timing for unused routing resources in connection blocks */
|
||||||
|
print_analysis_sdc_disable_unused_cbs(fp, L_grids, module_manager,
|
||||||
|
L_device_rr_gsb,
|
||||||
|
compact_routing_hierarchy);
|
||||||
|
|
||||||
/* TODO: Apply to Connection blocks */
|
/* TODO: Disable timing for unused routing resources in switch blocks */
|
||||||
/*
|
|
||||||
if (TRUE == compact_routing_hierarchy) {
|
|
||||||
verilog_generate_sdc_disable_unused_cbs(fp, LL_nx, LL_ny, LL_device_rr_gsb);
|
|
||||||
verilog_generate_sdc_disable_unused_cbs_muxs(fp, LL_nx, LL_ny, LL_device_rr_gsb);
|
|
||||||
} else {
|
|
||||||
verilog_generate_sdc_disable_unused_cbs(fp, LL_nx, LL_ny);
|
|
||||||
verilog_generate_sdc_disable_unused_cbs_muxs(fp, LL_nx, LL_ny);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* TODO: Apply to Switch blocks */
|
|
||||||
/*
|
/*
|
||||||
if (TRUE == compact_routing_hierarchy) {
|
if (TRUE == compact_routing_hierarchy) {
|
||||||
verilog_generate_sdc_disable_unused_sbs(fp);
|
verilog_generate_sdc_disable_unused_sbs(fp);
|
||||||
|
@ -265,7 +258,7 @@ void print_analysis_sdc(const std::string& sdc_dir,
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* TODO: Apply to Grids */
|
/* TODO: Disable timing for unused routing resources in grids (programmable blocks) */
|
||||||
/*
|
/*
|
||||||
verilog_generate_sdc_disable_unused_grids(fp, LL_nx, LL_ny, LL_grid, LL_block);
|
verilog_generate_sdc_disable_unused_grids(fp, LL_nx, LL_ny, LL_grid, LL_block);
|
||||||
verilog_generate_sdc_disable_unused_grids_muxs(fp, LL_nx, LL_ny, LL_grid, LL_block);
|
verilog_generate_sdc_disable_unused_grids_muxs(fp, LL_nx, LL_ny, LL_grid, LL_block);
|
||||||
|
|
|
@ -25,7 +25,7 @@ void fpga_sdc_generator(const SdcOption& sdc_options,
|
||||||
const std::vector<CircuitPortId>& global_ports,
|
const std::vector<CircuitPortId>& global_ports,
|
||||||
const bool& compact_routing_hierarchy) {
|
const bool& compact_routing_hierarchy) {
|
||||||
vpr_printf(TIO_MESSAGE_INFO,
|
vpr_printf(TIO_MESSAGE_INFO,
|
||||||
"SDC generator starts...");
|
"SDC generator starts...\n");
|
||||||
|
|
||||||
/* Start time count */
|
/* Start time count */
|
||||||
clock_t t_start = clock();
|
clock_t t_start = clock();
|
||||||
|
|
Loading…
Reference in New Issue