refactored analysis SDC generator for grids
This commit is contained in:
parent
6c58a4dd92
commit
d84cd66287
|
@ -10,6 +10,8 @@
|
|||
#include "fpga_x2p_utils.h"
|
||||
#include "fpga_x2p_pbtypes_utils.h"
|
||||
|
||||
#include "sdc_writer_utils.h"
|
||||
#include "analysis_sdc_writer_utils.h"
|
||||
#include "analysis_sdc_grid_writer.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
@ -30,6 +32,9 @@ void rec_print_analysis_sdc_disable_unused_pb_graph_nodes(std::fstream& fp,
|
|||
t_pb_graph_node* physical_pb_graph_node,
|
||||
const e_side& border_side) {
|
||||
t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type;
|
||||
|
||||
/* Validate file stream */
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Disable all the ports of current module (parent_module)!
|
||||
* Hierarchy name already includes the instance name of parent_module
|
||||
|
@ -72,23 +77,366 @@ void rec_print_analysis_sdc_disable_unused_pb_graph_nodes(std::fstream& fp,
|
|||
}
|
||||
|
||||
/********************************************************************
|
||||
* Disable an unused pin of a pb_graph_node (parent_module)
|
||||
*******************************************************************/
|
||||
static
|
||||
void disable_pb_graph_node_unused_pin(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& hierarchy_name,
|
||||
const t_pb_graph_pin& pb_graph_pin,
|
||||
t_phy_pb* block_physical_pb) {
|
||||
/* Validate file stream */
|
||||
check_file_handler(fp);
|
||||
|
||||
int rr_node_index = pb_graph_pin.rr_node_index_physical_pb;
|
||||
|
||||
/* Identify if the net has been used or not */
|
||||
if (false == is_rr_node_to_be_disable_for_analysis(&(block_physical_pb->rr_graph->rr_node[rr_node_index]))) {
|
||||
/* Used pin; Nothing to do */
|
||||
return;
|
||||
}
|
||||
/* Reach here, it means that this pin is not used. Disable timing analysis for the pin */
|
||||
/* Find the module port by name */
|
||||
std::string module_port_name = generate_pb_type_port_name(pb_graph_pin.port);
|
||||
ModulePortId module_port = module_manager.find_module_port(parent_module, module_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(parent_module, module_port));
|
||||
BasicPort port_to_disable = module_manager.module_port(parent_module, module_port);
|
||||
port_to_disable.set_width(pb_graph_pin.pin_number, pb_graph_pin.pin_number);
|
||||
|
||||
fp << "set_disable_timing ";
|
||||
fp << hierarchy_name;
|
||||
fp << "/";
|
||||
fp << generate_sdc_port(port_to_disable);
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Disable unused input ports and output ports of this pb_graph_node (parent_module)
|
||||
* This function will iterate over all the input pins, output pins
|
||||
* of the physical_pb_graph_node, and check if they are mapped
|
||||
* For unused pins, we will find the port in parent_module
|
||||
* and then print SDC commands to disable them
|
||||
*******************************************************************/
|
||||
static
|
||||
void disable_pb_graph_node_unused_pins(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& hierarchy_name,
|
||||
t_pb_graph_node* physical_pb_graph_node,
|
||||
t_phy_pb* block_physical_pb) {
|
||||
|
||||
/* Disable unused input pins */
|
||||
for (int iport = 0; iport < physical_pb_graph_node->num_input_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < physical_pb_graph_node->num_input_pins[iport]; ++ipin) {
|
||||
disable_pb_graph_node_unused_pin(fp, module_manager, parent_module,
|
||||
hierarchy_name,
|
||||
physical_pb_graph_node->input_pins[iport][ipin],
|
||||
block_physical_pb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable unused output pins */
|
||||
for (int iport = 0; iport < physical_pb_graph_node->num_output_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < physical_pb_graph_node->num_output_pins[iport]; ++ipin) {
|
||||
disable_pb_graph_node_unused_pin(fp, module_manager, parent_module,
|
||||
hierarchy_name,
|
||||
physical_pb_graph_node->output_pins[iport][ipin],
|
||||
block_physical_pb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable unused clock pins */
|
||||
for (int iport = 0; iport < physical_pb_graph_node->num_clock_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < physical_pb_graph_node->num_clock_pins[iport]; ++ipin) {
|
||||
disable_pb_graph_node_unused_pin(fp, module_manager, parent_module,
|
||||
hierarchy_name,
|
||||
physical_pb_graph_node->clock_pins[iport][ipin],
|
||||
block_physical_pb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Disable unused inputs of routing multiplexers of this pb_graph_node
|
||||
* This function will first cache the nets for each input and output pins
|
||||
* and store the results in a mux_name-to-net mapping
|
||||
*******************************************************************/
|
||||
static
|
||||
void disable_pb_graph_node_unused_mux_inputs(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& hierarchy_name,
|
||||
t_pb_graph_node* physical_pb_graph_node,
|
||||
t_phy_pb* block_physical_pb,
|
||||
const e_side& border_side) {
|
||||
t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type;
|
||||
|
||||
int physical_mode_index = find_pb_type_physical_mode_index(*physical_pb_type);
|
||||
|
||||
std::map<std::string, int> mux_instance_to_net_map;
|
||||
|
||||
/* Cache the nets for each input pins of each child pb_graph_node */
|
||||
for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) {
|
||||
for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) {
|
||||
|
||||
t_pb_graph_node* child_pb_graph_node = &(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]);
|
||||
|
||||
/* Cache the nets for input pins of the child pb_graph_node */
|
||||
for (int iport = 0; iport < child_pb_graph_node->num_input_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < child_pb_graph_node->num_input_pins[iport]; ++ipin) {
|
||||
int rr_node_index = child_pb_graph_node->input_pins[iport][ipin].rr_node_index_physical_pb;
|
||||
/* Generate the mux name */
|
||||
std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, &(child_pb_graph_node->input_pins[iport][ipin]), std::string(""));
|
||||
/* Cache the net */
|
||||
mux_instance_to_net_map[mux_instance_name] = block_physical_pb->rr_graph->rr_node[rr_node_index].vpack_net_num;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cache the nets for clock pins of the child pb_graph_node */
|
||||
for (int iport = 0; iport < child_pb_graph_node->num_clock_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < child_pb_graph_node->num_clock_pins[iport]; ++ipin) {
|
||||
int rr_node_index = child_pb_graph_node->clock_pins[iport][ipin].rr_node_index_physical_pb;
|
||||
/* Generate the mux name */
|
||||
std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, &(child_pb_graph_node->clock_pins[iport][ipin]), std::string(""));
|
||||
/* Cache the net */
|
||||
mux_instance_to_net_map[mux_instance_name] = block_physical_pb->rr_graph->rr_node[rr_node_index].vpack_net_num;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Cache the nets for each output pins of this pb_graph_node */
|
||||
for (int iport = 0; iport < physical_pb_graph_node->num_output_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < physical_pb_graph_node->num_output_pins[iport]; ++ipin) {
|
||||
int rr_node_index = physical_pb_graph_node->output_pins[iport][ipin].rr_node_index_physical_pb;
|
||||
/* Generate the mux name */
|
||||
std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, &(physical_pb_graph_node->output_pins[iport][ipin]), std::string(""));
|
||||
/* Cache the net */
|
||||
mux_instance_to_net_map[mux_instance_name] = block_physical_pb->rr_graph->rr_node[rr_node_index].vpack_net_num;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now disable unused inputs of routing multiplexers, by tracing from input pins of the parent_module */
|
||||
for (int iport = 0; iport < physical_pb_graph_node->num_input_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < physical_pb_graph_node->num_input_pins[iport]; ++ipin) {
|
||||
/* Find the module port by name */
|
||||
std::string module_port_name = generate_pb_type_port_name(physical_pb_graph_node->input_pins[iport][ipin].port);
|
||||
ModulePortId module_port = module_manager.find_module_port(parent_module, module_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(parent_module, module_port));
|
||||
|
||||
int rr_node_index = physical_pb_graph_node->input_pins[iport][ipin].rr_node_index_physical_pb;
|
||||
t_rr_node* input_rr_node = &(block_physical_pb->rr_graph->rr_node[rr_node_index]);
|
||||
|
||||
disable_analysis_module_input_pin_net_sinks(fp, module_manager, parent_module,
|
||||
hierarchy_name,
|
||||
module_port, ipin,
|
||||
input_rr_node,
|
||||
mux_instance_to_net_map);
|
||||
}
|
||||
}
|
||||
|
||||
for (int iport = 0; iport < physical_pb_graph_node->num_clock_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < physical_pb_graph_node->num_clock_pins[iport]; ++ipin) {
|
||||
/* Find the module port by name */
|
||||
std::string module_port_name = generate_pb_type_port_name(physical_pb_graph_node->clock_pins[iport][ipin].port);
|
||||
ModulePortId module_port = module_manager.find_module_port(parent_module, module_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(parent_module, module_port));
|
||||
|
||||
int rr_node_index = physical_pb_graph_node->clock_pins[iport][ipin].rr_node_index_physical_pb;
|
||||
t_rr_node* input_rr_node = &(block_physical_pb->rr_graph->rr_node[rr_node_index]);
|
||||
|
||||
disable_analysis_module_input_pin_net_sinks(fp, module_manager, parent_module,
|
||||
hierarchy_name,
|
||||
module_port, ipin,
|
||||
input_rr_node,
|
||||
mux_instance_to_net_map);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now disable unused inputs of routing multiplexers, by tracing from output pins of the child_module */
|
||||
for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) {
|
||||
/* Generate the name of the Verilog module for this child */
|
||||
std::string child_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side);
|
||||
std::string child_module_name = generate_physical_block_module_name(child_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild]));
|
||||
|
||||
ModuleId child_module = module_manager.find_module(child_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(child_module));
|
||||
|
||||
for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) {
|
||||
|
||||
t_pb_graph_node* child_pb_graph_node = &(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]);
|
||||
|
||||
for (int iport = 0; iport < child_pb_graph_node->num_output_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < child_pb_graph_node->num_output_pins[iport]; ++ipin) {
|
||||
/* Find the module port by name */
|
||||
std::string module_port_name = generate_pb_type_port_name(child_pb_graph_node->output_pins[iport][ipin].port);
|
||||
ModulePortId module_port = module_manager.find_module_port(child_module, module_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(child_module, module_port));
|
||||
|
||||
int rr_node_index = child_pb_graph_node->output_pins[iport][ipin].rr_node_index_physical_pb;
|
||||
t_rr_node* output_rr_node = &(block_physical_pb->rr_graph->rr_node[rr_node_index]);
|
||||
|
||||
disable_analysis_module_output_pin_net_sinks(fp, module_manager, parent_module,
|
||||
hierarchy_name,
|
||||
child_module, inst,
|
||||
module_port, ipin,
|
||||
output_rr_node,
|
||||
mux_instance_to_net_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Recursively visit all the pb_types in the hierarchy
|
||||
* and disable all the unused resources, including:
|
||||
* 1. input ports
|
||||
* 2. output ports
|
||||
* 3. unused inputs of routing multiplexers
|
||||
*
|
||||
* As this function is executed in a recursive way.
|
||||
* To avoid repeated disable timing for ports, during each run of this function,
|
||||
* only the unused input ports, output ports of the parent module will be disabled.
|
||||
* In addition, we will cache all the net ids mapped to the input ports of
|
||||
* child modules, and the net ids mapped to the output ports of parent module.
|
||||
* As such, we can trace from
|
||||
* 1. the input ports of parent module to disable unused inputs of routing multiplexer
|
||||
* which drives the inputs of child modules
|
||||
*
|
||||
* Parent_module
|
||||
* +---------------------------------------------
|
||||
* | MUX child_module
|
||||
* | +-------------+ +--------
|
||||
* input_pin0(netA) --->|-------->| Routing |------>|
|
||||
* input_pin1(netB) --->|----x--->| Multiplexer | netA |
|
||||
* | +-------------+ |
|
||||
* | |
|
||||
*
|
||||
* 2. the output ports of child module to disable unused inputs of routing multiplexer
|
||||
* which drives the outputs of parent modules
|
||||
*
|
||||
* Case 1:
|
||||
* parent_module
|
||||
* --------------------------------------+
|
||||
* child_module |
|
||||
* -------------+ |
|
||||
* | +-------------+ |
|
||||
* output_pin0 (netA) |--->| Routing |----->|---->
|
||||
* output_pin1 (netB) |-x->| Multiplexer | netA |
|
||||
* | +-------------+ |
|
||||
*
|
||||
* Case 2:
|
||||
*
|
||||
* Parent_module
|
||||
* +---------------------------------------------
|
||||
* |
|
||||
* | +--------------------------------------------+
|
||||
* | | MUX child_module |
|
||||
* | | +-------------+ +-----------+ |
|
||||
* | +--->| Routing |------>| | |
|
||||
* input_pin0(netA) --->|----x--->| Multiplexer | netA | output_pin|-----+
|
||||
* | +-------------+ | | netA
|
||||
* | | |
|
||||
*
|
||||
*
|
||||
* Note: it is a must to disable all the ports in all the child pb_types!
|
||||
* This can prohibit timing analyzer to consider any FF-to-FF path or
|
||||
* combinatinal path inside an unused grid, when finding critical paths!!!
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_print_analysis_sdc_disable_pb_graph_node_unused_resources(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& hierarchy_name,
|
||||
t_pb_graph_node* physical_pb_graph_node,
|
||||
t_phy_pb* block_physical_pb,
|
||||
const e_side& border_side) {
|
||||
t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type;
|
||||
|
||||
/* Disable unused input ports and output ports of this pb_graph_node (parent_module) */
|
||||
disable_pb_graph_node_unused_pins(fp, module_manager, parent_module,
|
||||
hierarchy_name, physical_pb_graph_node, block_physical_pb);
|
||||
|
||||
/* Return if this is the primitive pb_type
|
||||
* Note: this must return before we disable any unused inputs of routing multiplexer!
|
||||
* This is due to that primitive pb_type does NOT contain any routing multiplexers inside!!!
|
||||
*/
|
||||
if (TRUE == is_primitive_pb_type(physical_pb_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disable unused inputs of routing multiplexers of this pb_graph_node */
|
||||
disable_pb_graph_node_unused_mux_inputs(fp, module_manager, parent_module,
|
||||
hierarchy_name, physical_pb_graph_node, block_physical_pb,
|
||||
border_side);
|
||||
|
||||
|
||||
int physical_mode_index = find_pb_type_physical_mode_index(*physical_pb_type);
|
||||
|
||||
/* Disable all the ports by iterating over its instance in the parent module */
|
||||
for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) {
|
||||
/* Generate the name of the Verilog module for this child */
|
||||
std::string child_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side);
|
||||
std::string child_module_name = generate_physical_block_module_name(child_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild]));
|
||||
|
||||
ModuleId child_module = module_manager.find_module(child_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(child_module));
|
||||
|
||||
/* Each child may exist multiple times in the hierarchy*/
|
||||
for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) {
|
||||
std::string child_instance_name = module_manager.instance_name(parent_module, child_module, module_manager.child_module_instances(parent_module, child_module)[inst]);
|
||||
/* Must have a valid instance name!!! */
|
||||
VTR_ASSERT(false == child_instance_name.empty());
|
||||
|
||||
std::string updated_hierarchy_name = hierarchy_name + std::string("/") + child_instance_name + std::string("/");
|
||||
|
||||
rec_print_analysis_sdc_disable_pb_graph_node_unused_resources(fp, module_manager, child_module, hierarchy_name,
|
||||
&(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]),
|
||||
block_physical_pb, border_side);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function can work in two differnt modes:
|
||||
* 1. For partially unused pb blocks
|
||||
* ---------------------------------
|
||||
* Disable the timing for only unused resources in a physical block
|
||||
* We have to walk through pb_graph node, port by port and pin by pin.
|
||||
* Identify which pins have not been used, and then disable the timing
|
||||
* for these ports.
|
||||
* Plus, for input ports, we will trace the routing multiplexers
|
||||
* and disable the timing for unused inputs.
|
||||
*
|
||||
* 2. For fully unused pb_blocks
|
||||
* -----------------------------
|
||||
* Disable the timing for a fully unused grid!
|
||||
* This is very straightforward!
|
||||
* Just walk through each pb_type and disable all the ports using wildcards
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_analysis_sdc_disable_unused_pb_block(std::fstream& fp,
|
||||
t_type_ptr grid_type,
|
||||
const vtr::Point<size_t>& grid_coordinate,
|
||||
const ModuleManager& module_manager,
|
||||
const std::string& grid_instance_name,
|
||||
const size_t& grid_z,
|
||||
const e_side& border_side) {
|
||||
void print_analysis_sdc_disable_pb_block_unused_resources(std::fstream& fp,
|
||||
t_type_ptr grid_type,
|
||||
const vtr::Point<size_t>& grid_coordinate,
|
||||
const ModuleManager& module_manager,
|
||||
const std::string& grid_instance_name,
|
||||
const size_t& grid_z,
|
||||
const e_side& border_side,
|
||||
t_phy_pb* block_physical_pb,
|
||||
const bool& unused_block) {
|
||||
/* Check code: if this is an IO block, the border side MUST be valid */
|
||||
if (IO_TYPE == grid_type) {
|
||||
VTR_ASSERT(NUM_SIDES != border_side);
|
||||
}
|
||||
|
||||
/* If the block is partially unused, we should have a physical pb */
|
||||
if (false == unused_block) {
|
||||
VTR_ASSERT(NULL != block_physical_pb);
|
||||
}
|
||||
|
||||
/* Find an unique name to the pb instance in this grid
|
||||
* Note: this must be consistent with the instance name we used in build_grid_module()!!!
|
||||
*/
|
||||
|
@ -102,13 +450,25 @@ void print_analysis_sdc_disable_unused_pb_block(std::fstream& fp,
|
|||
|
||||
/* Print comments */
|
||||
fp << "#######################################" << std::endl;
|
||||
fp << "# Disable Timing for unused grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "][" << grid_z << "]" << std::endl;
|
||||
|
||||
if (true == unused_block) {
|
||||
fp << "# Disable Timing for unused grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "][" << grid_z << "]" << std::endl;
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(false == unused_block);
|
||||
fp << "# Disable Timing for unused resources in grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "][" << grid_z << "]" << std::endl;
|
||||
}
|
||||
|
||||
fp << "#######################################" << std::endl;
|
||||
|
||||
std::string hierarchy_name = grid_instance_name + std::string("/") + pb_instance_name + std::string("/");
|
||||
|
||||
/* Go recursively through the pb_graph hierarchy, and disable all the ports level by level */
|
||||
rec_print_analysis_sdc_disable_unused_pb_graph_nodes(fp, module_manager, pb_module, hierarchy_name, grid_type->pb_graph_head, border_side);
|
||||
if (true == unused_block) {
|
||||
rec_print_analysis_sdc_disable_unused_pb_graph_nodes(fp, module_manager, pb_module, hierarchy_name, grid_type->pb_graph_head, border_side);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(false == unused_block);
|
||||
rec_print_analysis_sdc_disable_pb_graph_node_unused_resources(fp, module_manager, pb_module, hierarchy_name, grid_type->pb_graph_head, block_physical_pb, border_side);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
@ -133,7 +493,7 @@ void print_analysis_sdc_disable_unused_grid(std::fstream& fp,
|
|||
*/
|
||||
if ( (NULL == grid_type)
|
||||
|| (EMPTY_TYPE == grid_type)
|
||||
|| (0 == L_grids[grid_coordinate.x()][grid_coordinate.y()].offset) ) {
|
||||
|| (0 < L_grids[grid_coordinate.x()][grid_coordinate.y()].offset) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -168,6 +528,8 @@ void print_analysis_sdc_disable_unused_grid(std::fstream& fp,
|
|||
/* TODO:
|
||||
verilog_generate_sdc_disable_one_unused_block(fp, &(L_blocks[blk_id]));
|
||||
*/
|
||||
t_phy_pb* block_phy_pb = (t_phy_pb*) L_blocks[blk_id].phy_pb;
|
||||
print_analysis_sdc_disable_pb_block_unused_resources(fp, grid_type, grid_coordinate, module_manager, grid_instance_name, iblk, border_side, block_phy_pb, false);
|
||||
}
|
||||
|
||||
/* For unused grid, disable all the pins in the physical_pb_type */
|
||||
|
@ -176,7 +538,7 @@ void print_analysis_sdc_disable_unused_grid(std::fstream& fp,
|
|||
if (true == grid_usage[iblk]) {
|
||||
continue;
|
||||
}
|
||||
print_analysis_sdc_disable_unused_pb_block(fp, grid_type, grid_coordinate, module_manager, grid_instance_name, iblk, border_side);
|
||||
print_analysis_sdc_disable_pb_block_unused_resources(fp, grid_type, grid_coordinate, module_manager, grid_instance_name, iblk, border_side, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,9 +569,6 @@ void print_analysis_sdc_disable_unused_grids(std::fstream& fp,
|
|||
const std::vector<std::vector<t_grid_tile>>& L_grids,
|
||||
const std::vector<t_block>& L_blocks,
|
||||
const ModuleManager& module_manager) {
|
||||
/* TODO: disable inputs of multiplexers
|
||||
verilog_generate_sdc_disable_unused_grids_muxs(fp, LL_nx, LL_ny, LL_grid, LL_block);
|
||||
*/
|
||||
|
||||
/* Process unused core grids */
|
||||
for (size_t ix = 1; ix < device_size.x() - 1; ++ix) {
|
||||
|
|
|
@ -14,107 +14,11 @@
|
|||
#include "fpga_x2p_types.h"
|
||||
|
||||
#include "sdc_writer_utils.h"
|
||||
#include "analysis_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;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Disable all the unused inputs of routing multiplexers, which are not used by benchmark
|
||||
* Here, we start from each input of a routing module, and traverse forward to the sink
|
||||
* port of the module net whose source is the input
|
||||
* We will find the instance name which is the parent of the sink port, and search the
|
||||
* net id through the instance_name_to_net_map
|
||||
* The the net id does not match the net id of this input, we will disable the sink port!
|
||||
*
|
||||
* parent_module
|
||||
* +-----------------------
|
||||
* | MUX instance A
|
||||
* | +-----------
|
||||
* input_port--->|--+---x-->| sink port (disable! net_id = Y)
|
||||
* (net_id = X) | | +----------
|
||||
* | | MUX instance B
|
||||
* | | +----------
|
||||
* | +------>| sink port (do not disable! net_id = X)
|
||||
*
|
||||
*******************************************************************/
|
||||
static
|
||||
void disable_analysis_module_input_port_net_sinks(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& parent_instance_name,
|
||||
const ModulePortId& module_input_port,
|
||||
t_rr_node* input_rr_node,
|
||||
const std::map<std::string, int> mux_instance_to_net_map) {
|
||||
/* Validate file stream */
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Find the module net which sources from this port! */
|
||||
for (const size_t& pin : module_manager.module_port(parent_module, module_input_port).pins()) {
|
||||
ModuleNetId module_net = module_manager.module_instance_port_net(parent_module, parent_module, 0, module_input_port, pin);
|
||||
VTR_ASSERT(true == module_manager.valid_module_net_id(parent_module, module_net));
|
||||
|
||||
/* Touch each sink of the net! */
|
||||
for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(parent_module, module_net)) {
|
||||
ModuleId sink_module = module_manager.net_sink_modules(parent_module, module_net)[sink_id];
|
||||
size_t sink_instance = module_manager.net_sink_instances(parent_module, module_net)[sink_id];
|
||||
|
||||
/* Skip when sink module is the parent module,
|
||||
* the output ports of parent modules have been disabled/enabled already!
|
||||
*/
|
||||
if (sink_module == parent_module) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string sink_instance_name = module_manager.instance_name(parent_module, sink_module, sink_instance);
|
||||
bool disable_timing = false;
|
||||
/* Check if this node is used by benchmark */
|
||||
if (true == is_rr_node_to_be_disable_for_analysis(input_rr_node)) {
|
||||
/* Disable all the sinks! */
|
||||
disable_timing = true;
|
||||
} else {
|
||||
/* See if the net id matches. If does not match, we should disable! */
|
||||
if (input_rr_node->vpack_net_num != mux_instance_to_net_map.at(sink_instance_name)) {
|
||||
disable_timing = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Time to write SDC command to disable timing or not */
|
||||
if (false == disable_timing) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(parent_module, module_net)[sink_id]);
|
||||
sink_port.set_width(module_manager.net_sink_pins(parent_module, module_net)[sink_id],
|
||||
module_manager.net_sink_pins(parent_module, module_net)[sink_id]);
|
||||
/* Get the input id that is used! Disable the unused inputs! */
|
||||
fp << "set_disable_timing ";
|
||||
fp << parent_instance_name << "/";
|
||||
fp << sink_instance_name << "/";
|
||||
fp << generate_sdc_port(sink_port);
|
||||
fp << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will disable
|
||||
* 1. all the unused port (unmapped by a benchmark) of a connection block
|
||||
|
|
|
@ -255,7 +255,7 @@ void print_analysis_sdc(const std::string& sdc_dir,
|
|||
L_device_rr_gsb,
|
||||
compact_routing_hierarchy);
|
||||
|
||||
/* TODO: Disable timing for unused routing resources in grids (programmable blocks) */
|
||||
/* Disable timing for unused routing resources in grids (programmable blocks) */
|
||||
print_analysis_sdc_disable_unused_grids(fp, device_size, L_grids, L_blocks, module_manager);
|
||||
|
||||
/* Close file handler */
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
/********************************************************************
|
||||
* This file includes most utilized functions
|
||||
* that are used to output a SDC file
|
||||
* in order to constrain a FPGA fabric (P&Red netlist) mapped to a benchmark
|
||||
*******************************************************************/
|
||||
#include "vtr_assert.h"
|
||||
|
||||
#include "fpga_x2p_utils.h"
|
||||
|
||||
#include "sdc_writer_utils.h"
|
||||
#include "analysis_sdc_writer_utils.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
/********************************************************************
|
||||
* Identify if a node should be disabled during analysis SDC generation
|
||||
*******************************************************************/
|
||||
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;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Disable all the unused inputs of routing multiplexers, which are not used by benchmark
|
||||
* Here, we start from each input of a routing module, and traverse forward to the sink
|
||||
* port of the module net whose source is the input
|
||||
* We will find the instance name which is the parent of the sink port, and search the
|
||||
* net id through the instance_name_to_net_map
|
||||
* The the net id does not match the net id of this input, we will disable the sink port!
|
||||
*
|
||||
* parent_module
|
||||
* +-----------------------
|
||||
* | MUX instance A
|
||||
* | +-----------
|
||||
* input_port--->|--+---x-->| sink port (disable! net_id = Y)
|
||||
* (net_id = X) | | +----------
|
||||
* | | MUX instance B
|
||||
* | | +----------
|
||||
* | +------>| sink port (do not disable! net_id = X)
|
||||
*
|
||||
*******************************************************************/
|
||||
void disable_analysis_module_input_pin_net_sinks(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& parent_instance_name,
|
||||
const ModulePortId& module_input_port,
|
||||
const size_t& module_input_pin,
|
||||
t_rr_node* input_rr_node,
|
||||
const std::map<std::string, int> mux_instance_to_net_map) {
|
||||
/* Validate file stream */
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Find the module net which sources from this port! */
|
||||
ModuleNetId module_net = module_manager.module_instance_port_net(parent_module, parent_module, 0, module_input_port, module_input_pin);
|
||||
VTR_ASSERT(true == module_manager.valid_module_net_id(parent_module, module_net));
|
||||
|
||||
/* Touch each sink of the net! */
|
||||
for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(parent_module, module_net)) {
|
||||
ModuleId sink_module = module_manager.net_sink_modules(parent_module, module_net)[sink_id];
|
||||
size_t sink_instance = module_manager.net_sink_instances(parent_module, module_net)[sink_id];
|
||||
|
||||
/* Skip when sink module is the parent module,
|
||||
* the output ports of parent modules have been disabled/enabled already!
|
||||
*/
|
||||
if (sink_module == parent_module) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string sink_instance_name = module_manager.instance_name(parent_module, sink_module, sink_instance);
|
||||
bool disable_timing = false;
|
||||
/* Check if this node is used by benchmark */
|
||||
if (true == is_rr_node_to_be_disable_for_analysis(input_rr_node)) {
|
||||
/* Disable all the sinks! */
|
||||
disable_timing = true;
|
||||
} else {
|
||||
std::map<std::string, int>::const_iterator it = mux_instance_to_net_map.find(sink_instance_name);
|
||||
if (it != mux_instance_to_net_map.end()) {
|
||||
/* See if the net id matches. If does not match, we should disable! */
|
||||
if (input_rr_node->vpack_net_num != mux_instance_to_net_map.at(sink_instance_name)) {
|
||||
disable_timing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Time to write SDC command to disable timing or not */
|
||||
if (false == disable_timing) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(parent_module, module_net)[sink_id]);
|
||||
sink_port.set_width(module_manager.net_sink_pins(parent_module, module_net)[sink_id],
|
||||
module_manager.net_sink_pins(parent_module, module_net)[sink_id]);
|
||||
/* Get the input id that is used! Disable the unused inputs! */
|
||||
fp << "set_disable_timing ";
|
||||
fp << parent_instance_name << "/";
|
||||
fp << sink_instance_name << "/";
|
||||
fp << generate_sdc_port(sink_port);
|
||||
fp << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Disable all the unused inputs of routing multiplexers, which are not used by benchmark
|
||||
* Here, we start from each input of a routing module, and traverse forward to the sink
|
||||
* port of the module net whose source is the input
|
||||
* We will find the instance name which is the parent of the sink port, and search the
|
||||
* net id through the instance_name_to_net_map
|
||||
* The the net id does not match the net id of this input, we will disable the sink port!
|
||||
*
|
||||
* parent_module
|
||||
* +-----------------------
|
||||
* | MUX instance A
|
||||
* | +-----------
|
||||
* input_port--->|--+---x-->| sink port (disable! net_id = Y)
|
||||
* (net_id = X) | | +----------
|
||||
* | | MUX instance B
|
||||
* | | +----------
|
||||
* | +------>| sink port (do not disable! net_id = X)
|
||||
*
|
||||
*******************************************************************/
|
||||
void disable_analysis_module_input_port_net_sinks(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& parent_instance_name,
|
||||
const ModulePortId& module_input_port,
|
||||
t_rr_node* input_rr_node,
|
||||
const std::map<std::string, int> mux_instance_to_net_map) {
|
||||
/* Validate file stream */
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Find the module net which sources from this port! */
|
||||
for (const size_t& pin : module_manager.module_port(parent_module, module_input_port).pins()) {
|
||||
disable_analysis_module_input_pin_net_sinks(fp, module_manager, parent_module,
|
||||
parent_instance_name,
|
||||
module_input_port, pin,
|
||||
input_rr_node,
|
||||
mux_instance_to_net_map);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Disable all the unused inputs of routing multiplexers, which are not used by benchmark
|
||||
* Here, we start from each output of a child module, and traverse forward to the sink
|
||||
* port of the module net whose source is the input
|
||||
* We will find the instance name which is the parent of the sink port, and search the
|
||||
* net id through the instance_name_to_net_map
|
||||
* The the net id does not match the net id of this input, we will disable the sink port!
|
||||
*
|
||||
* Parent_module
|
||||
* +---------------------------------------------
|
||||
* |
|
||||
* | +--------------------------------------------+
|
||||
* | | MUX child_module |
|
||||
* | | +-------------+ +-----------+ |
|
||||
* | +--->| Routing |------>| | |
|
||||
* input_pin0(netA) --->|----x--->| Multiplexer | netA | output_pin|-----+
|
||||
* | +-------------+ | | netA
|
||||
* | | |
|
||||
*
|
||||
|
||||
*
|
||||
*******************************************************************/
|
||||
void disable_analysis_module_output_pin_net_sinks(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& parent_instance_name,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance,
|
||||
const ModulePortId& child_module_port,
|
||||
const size_t& child_module_pin,
|
||||
t_rr_node* output_rr_node,
|
||||
const std::map<std::string, int> mux_instance_to_net_map) {
|
||||
/* Validate file stream */
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Find the module net which sources from this port! */
|
||||
ModuleNetId module_net = module_manager.module_instance_port_net(parent_module, child_module, child_instance, child_module_port, child_module_pin);
|
||||
VTR_ASSERT(true == module_manager.valid_module_net_id(parent_module, module_net));
|
||||
|
||||
/* Touch each sink of the net! */
|
||||
for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(parent_module, module_net)) {
|
||||
ModuleId sink_module = module_manager.net_sink_modules(parent_module, module_net)[sink_id];
|
||||
size_t sink_instance = module_manager.net_sink_instances(parent_module, module_net)[sink_id];
|
||||
|
||||
/* Skip when sink module is the parent module,
|
||||
* the output ports of parent modules have been disabled/enabled already!
|
||||
*/
|
||||
if (sink_module == parent_module) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string sink_instance_name = module_manager.instance_name(parent_module, sink_module, sink_instance);
|
||||
bool disable_timing = false;
|
||||
/* Check if this node is used by benchmark */
|
||||
if (true == is_rr_node_to_be_disable_for_analysis(output_rr_node)) {
|
||||
/* Disable all the sinks! */
|
||||
disable_timing = true;
|
||||
} else {
|
||||
std::map<std::string, int>::const_iterator it = mux_instance_to_net_map.find(sink_instance_name);
|
||||
if (it != mux_instance_to_net_map.end()) {
|
||||
/* See if the net id matches. If does not match, we should disable! */
|
||||
if (output_rr_node->vpack_net_num != mux_instance_to_net_map.at(sink_instance_name)) {
|
||||
disable_timing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Time to write SDC command to disable timing or not */
|
||||
if (false == disable_timing) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(parent_module, module_net)[sink_id]);
|
||||
sink_port.set_width(module_manager.net_sink_pins(parent_module, module_net)[sink_id],
|
||||
module_manager.net_sink_pins(parent_module, module_net)[sink_id]);
|
||||
/* Get the input id that is used! Disable the unused inputs! */
|
||||
fp << "set_disable_timing ";
|
||||
fp << parent_instance_name << "/";
|
||||
fp << sink_instance_name << "/";
|
||||
fp << generate_sdc_port(sink_port);
|
||||
fp << std::endl;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef ANALYSIS_SDC_WRITER_UTILS_H
|
||||
#define ANALYSIS_SDC_WRITER_UTILS_H
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "module_manager.h"
|
||||
#include "vpr_types.h"
|
||||
|
||||
bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node);
|
||||
|
||||
void disable_analysis_module_input_pin_net_sinks(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& parent_instance_name,
|
||||
const ModulePortId& module_input_port,
|
||||
const size_t& module_input_pin,
|
||||
t_rr_node* input_rr_node,
|
||||
const std::map<std::string, int> mux_instance_to_net_map);
|
||||
|
||||
void disable_analysis_module_input_port_net_sinks(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& parent_instance_name,
|
||||
const ModulePortId& module_input_port,
|
||||
t_rr_node* input_rr_node,
|
||||
const std::map<std::string, int> mux_instance_to_net_map) ;
|
||||
|
||||
void disable_analysis_module_output_pin_net_sinks(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& parent_instance_name,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance,
|
||||
const ModulePortId& child_module_port,
|
||||
const size_t& child_module_pin,
|
||||
t_rr_node* output_rr_node,
|
||||
const std::map<std::string, int> mux_instance_to_net_map);
|
||||
|
||||
#endif
|
|
@ -483,7 +483,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
|
|||
}
|
||||
|
||||
/* Initialize the interconnection type that will be physically implemented in module */
|
||||
enum e_interconnect verilog_interc_type = determine_actual_pb_interc_type(cur_interc, fan_in);
|
||||
enum e_interconnect interc_type = determine_actual_pb_interc_type(cur_interc, fan_in);
|
||||
|
||||
/* Find input ports of the wire module */
|
||||
std::vector<CircuitPortId> interc_model_inputs = circuit_lib.model_ports_by_type(cur_interc->circuit_model, SPICE_MODEL_PORT_INPUT, true); /* the last argument to guarantee that we ignore any global inputs */
|
||||
|
@ -497,7 +497,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
|
|||
/* Branch on the type of physical implementation,
|
||||
* We add instances of programmable interconnection
|
||||
*/
|
||||
switch (verilog_interc_type) {
|
||||
switch (interc_type) {
|
||||
case DIRECT_INTERC: {
|
||||
/* Ensure direct interc has only one fan-in */
|
||||
VTR_ASSERT(1 == fan_in);
|
||||
|
@ -521,7 +521,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager,
|
|||
/* Get the instance id and add an instance of wire */
|
||||
size_t wire_instance = module_manager.num_instance(pb_module, wire_module);
|
||||
module_manager.add_child_module(pb_module, wire_module);
|
||||
|
||||
|
||||
/* Ensure input and output ports of the wire model has only 1 pin respectively */
|
||||
VTR_ASSERT(1 == circuit_lib.port_size(interc_model_inputs[0]));
|
||||
VTR_ASSERT(1 == circuit_lib.port_size(interc_model_outputs[0]));
|
||||
|
|
Loading…
Reference in New Issue