diff --git a/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp b/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp index 167ec497b..c88e3e2ef 100644 --- a/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp +++ b/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp @@ -29,6 +29,7 @@ #include "sdc_writer_naming.h" #include "sdc_writer_utils.h" #include "sdc_memory_utils.h" +#include "sdc_mux_utils.h" #include "pnr_sdc_global_port.h" #include "pnr_sdc_routing_writer.h" #include "pnr_sdc_grid_writer.h" @@ -80,9 +81,11 @@ void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_ *******************************************************************/ static void print_sdc_disable_routing_multiplexer_outputs(const std::string& sdc_dir, + const bool& flatten_names, const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, - const ModuleManager& module_manager) { + const ModuleManager& module_manager, + const ModuleId& top_module) { /* Create the file name for Verilog netlist */ std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_MUX_OUTPUTS_FILE_NAME)); @@ -112,16 +115,22 @@ void print_sdc_disable_routing_multiplexer_outputs(const std::string& sdc_dir, std::string mux_module_name = generate_mux_subckt_name(circuit_lib, mux_model, find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()), std::string("")); + /* Find the module name in module manager */ ModuleId mux_module = module_manager.find_module(mux_module_name); VTR_ASSERT(true == module_manager.valid_module_id(mux_module)); - - /* Disable the timing for the output ports */ - for (const BasicPort& output_port : module_manager.module_ports_by_type(mux_module, ModuleManager::MODULE_OUTPUT_PORT)) { - fp << "set_disable_timing [get_pins -filter \"name =~ " << output_port.get_name() << "*\" "; - fp << "-of [get_cells -hier -filter \"ref_lib_cell_name == " << mux_module_name << "\"]]" << std::endl; - fp << std::endl; - } + + /* Go recursively in the module manager, + * starting from the top-level module: instance id of the top-level module is 0 by default + * Disable all the outputs of child modules that matches the mux_module id + */ + rec_print_pnr_sdc_disable_routing_multiplexer_outputs(fp, + flatten_names, + module_manager, + top_module, + mux_module, + format_dir_path(module_manager.module_name(top_module))); + } /* Close file handler */ @@ -398,14 +407,19 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options, /* Output Design Constraints to disable outputs of memory cells */ if (true == sdc_options.constrain_configurable_memory_outputs()) { - print_pnr_sdc_constrain_configurable_memory_outputs(sdc_options.sdc_dir(), sdc_options.flatten_names(), module_manager, top_module); + print_pnr_sdc_constrain_configurable_memory_outputs(sdc_options.sdc_dir(), + sdc_options.flatten_names(), + module_manager, + top_module); } /* Break loops from Multiplexer Output */ if (true == sdc_options.constrain_routing_multiplexer_outputs()) { print_sdc_disable_routing_multiplexer_outputs(sdc_options.sdc_dir(), + sdc_options.flatten_names(), mux_lib, circuit_lib, - module_manager); + module_manager, + top_module); } /* Break loops from any SB output */ diff --git a/openfpga/src/fpga_sdc/sdc_mux_utils.cpp b/openfpga/src/fpga_sdc/sdc_mux_utils.cpp new file mode 100644 index 000000000..ee30eae9b --- /dev/null +++ b/openfpga/src/fpga_sdc/sdc_mux_utils.cpp @@ -0,0 +1,113 @@ +/******************************************************************** + * Most utilized function used to constrain routing multiplexers in FPGA + * fabric using SDC commands + *******************************************************************/ + +/* Headers from vtrutil library */ +#include "vtr_assert.h" +#include "vtr_log.h" + +/* Headers from openfpgautil library */ +#include "openfpga_wildcard_string.h" +#include "openfpga_digest.h" + +#include "openfpga_naming.h" + +#include "sdc_writer_utils.h" + +#include "sdc_mux_utils.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/******************************************************************** + * Print SDC commands to disable outputs of routing multiplexer modules + * in a given module id + * This function will be executed in a recursive way, + * using a Depth-First Search (DFS) strategy + * It will iterate over all the configurable children under each module + * and print a SDC command to disable its outputs + * + * Note: + * - When flatten_names is true + * this function will not apply any wildcard to names + * - When flatten_names is false + * It will straightforwardly output the instance name and port name + * This function will try to apply wildcard to names + * so that SDC file size can be minimal + *******************************************************************/ +void rec_print_pnr_sdc_disable_routing_multiplexer_outputs(std::fstream& fp, + const bool& flatten_names, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const ModuleId& mux_module, + const std::string& parent_module_path) { + + /* Build wildcard names for the instance names of multiple-instanced-blocks (MIB) + * We will find all the instance names and see there are common prefix + * If so, we can use wildcards + */ + std::map> wildcard_names; + + /* For each child, we will go one level down in priority */ + for (const ModuleId& child_module : module_manager.child_modules(parent_module)) { + + std::string child_module_path = parent_module_path; + + /* Iterate over the child instances*/ + for (const size_t& child_instance : module_manager.child_module_instances(parent_module, child_module)) { + std::string child_instance_name; + if (true == module_manager.instance_name(parent_module, child_module, child_instance).empty()) { + child_instance_name = generate_instance_name(module_manager.module_name(child_module), child_instance); + } else { + child_instance_name = module_manager.instance_name(parent_module, child_module, child_instance); + } + + if (false == flatten_names) { + /* Try to adapt to a wildcard name: replace all the numbers with a wildcard character '*' */ + WildCardString wildcard_str(child_instance_name); + /* If the wildcard name is already in the list, we can skip this + * Otherwise, we have to + * - output this instance + * - record the wildcard name in the map + */ + if ( (0 < wildcard_names.count(child_module)) + && (wildcard_names.at(child_module).end() != std::find(wildcard_names.at(child_module).begin(), + wildcard_names.at(child_module).end(), + wildcard_str.data())) ) { + continue; + } + + child_module_path += wildcard_str.data(); + + wildcard_names[child_module].push_back(wildcard_str.data()); + } else { + child_module_path += child_instance_name; + } + + child_module_path = format_dir_path(child_module_path); + + /* If this is NOT the MUX module we want, we go recursively */ + if (mux_module != child_module) { + rec_print_pnr_sdc_disable_routing_multiplexer_outputs(fp, flatten_names, + module_manager, + child_module, + mux_module, + child_module_path); + continue; + } + + /* Validate file stream */ + valid_file_stream(fp); + + /* Reach here, this is the MUX module we want, disable the outputs */ + for (const BasicPort& output_port : module_manager.module_ports_by_type(mux_module, ModuleManager::MODULE_OUTPUT_PORT)) { + fp << "set_disable_timing "; + fp << child_module_path << output_port.get_name(); + fp << std::endl; + } + } + } +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/fpga_sdc/sdc_mux_utils.h b/openfpga/src/fpga_sdc/sdc_mux_utils.h new file mode 100644 index 000000000..70089aa93 --- /dev/null +++ b/openfpga/src/fpga_sdc/sdc_mux_utils.h @@ -0,0 +1,28 @@ +#ifndef SDC_MUX_UTILS_H +#define SDC_MUX_UTILS_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include +#include "module_manager.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +void rec_print_pnr_sdc_disable_routing_multiplexer_outputs(std::fstream& fp, + const bool& flatten_names, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const ModuleId& mux_module, + const std::string& parent_module_path); + + +} /* end namespace openfpga */ + +#endif