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_utils.h"
|
||||||
#include "fpga_x2p_pbtypes_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 "analysis_sdc_grid_writer.h"
|
||||||
|
|
||||||
#include "globals.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,
|
t_pb_graph_node* physical_pb_graph_node,
|
||||||
const e_side& border_side) {
|
const e_side& border_side) {
|
||||||
t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type;
|
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)!
|
/* Disable all the ports of current module (parent_module)!
|
||||||
* Hierarchy name already includes the instance name of 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!
|
* Disable the timing for a fully unused grid!
|
||||||
* This is very straightforward!
|
* This is very straightforward!
|
||||||
* Just walk through each pb_type and disable all the ports using wildcards
|
* Just walk through each pb_type and disable all the ports using wildcards
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static
|
static
|
||||||
void print_analysis_sdc_disable_unused_pb_block(std::fstream& fp,
|
void print_analysis_sdc_disable_pb_block_unused_resources(std::fstream& fp,
|
||||||
t_type_ptr grid_type,
|
t_type_ptr grid_type,
|
||||||
const vtr::Point<size_t>& grid_coordinate,
|
const vtr::Point<size_t>& grid_coordinate,
|
||||||
const ModuleManager& module_manager,
|
const ModuleManager& module_manager,
|
||||||
const std::string& grid_instance_name,
|
const std::string& grid_instance_name,
|
||||||
const size_t& grid_z,
|
const size_t& grid_z,
|
||||||
const e_side& border_side) {
|
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 */
|
/* Check code: if this is an IO block, the border side MUST be valid */
|
||||||
if (IO_TYPE == grid_type) {
|
if (IO_TYPE == grid_type) {
|
||||||
VTR_ASSERT(NUM_SIDES != border_side);
|
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
|
/* 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()!!!
|
* 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 */
|
/* Print comments */
|
||||||
fp << "#######################################" << std::endl;
|
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;
|
fp << "#######################################" << std::endl;
|
||||||
|
|
||||||
std::string hierarchy_name = grid_instance_name + std::string("/") + pb_instance_name + std::string("/");
|
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 */
|
/* 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)
|
if ( (NULL == grid_type)
|
||||||
|| (EMPTY_TYPE == 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +528,8 @@ void print_analysis_sdc_disable_unused_grid(std::fstream& fp,
|
||||||
/* TODO:
|
/* TODO:
|
||||||
verilog_generate_sdc_disable_one_unused_block(fp, &(L_blocks[blk_id]));
|
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 */
|
/* 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]) {
|
if (true == grid_usage[iblk]) {
|
||||||
continue;
|
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<std::vector<t_grid_tile>>& L_grids,
|
||||||
const std::vector<t_block>& L_blocks,
|
const std::vector<t_block>& L_blocks,
|
||||||
const ModuleManager& module_manager) {
|
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 */
|
/* Process unused core grids */
|
||||||
for (size_t ix = 1; ix < device_size.x() - 1; ++ix) {
|
for (size_t ix = 1; ix < device_size.x() - 1; ++ix) {
|
||||||
|
|
|
@ -14,107 +14,11 @@
|
||||||
#include "fpga_x2p_types.h"
|
#include "fpga_x2p_types.h"
|
||||||
|
|
||||||
#include "sdc_writer_utils.h"
|
#include "sdc_writer_utils.h"
|
||||||
|
#include "analysis_sdc_writer_utils.h"
|
||||||
#include "analysis_sdc_routing_writer.h"
|
#include "analysis_sdc_routing_writer.h"
|
||||||
|
|
||||||
#include "globals.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
|
* This function will disable
|
||||||
* 1. all the unused port (unmapped by a benchmark) of a connection block
|
* 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,
|
L_device_rr_gsb,
|
||||||
compact_routing_hierarchy);
|
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);
|
print_analysis_sdc_disable_unused_grids(fp, device_size, L_grids, L_blocks, module_manager);
|
||||||
|
|
||||||
/* Close file handler */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
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,
|
/* Branch on the type of physical implementation,
|
||||||
* We add instances of programmable interconnection
|
* We add instances of programmable interconnection
|
||||||
*/
|
*/
|
||||||
switch (verilog_interc_type) {
|
switch (interc_type) {
|
||||||
case DIRECT_INTERC: {
|
case DIRECT_INTERC: {
|
||||||
/* Ensure direct interc has only one fan-in */
|
/* Ensure direct interc has only one fan-in */
|
||||||
VTR_ASSERT(1 == 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 */
|
/* Get the instance id and add an instance of wire */
|
||||||
size_t wire_instance = module_manager.num_instance(pb_module, wire_module);
|
size_t wire_instance = module_manager.num_instance(pb_module, wire_module);
|
||||||
module_manager.add_child_module(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 */
|
/* 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_inputs[0]));
|
||||||
VTR_ASSERT(1 == circuit_lib.port_size(interc_model_outputs[0]));
|
VTR_ASSERT(1 == circuit_lib.port_size(interc_model_outputs[0]));
|
||||||
|
|
Loading…
Reference in New Issue