171 lines
7.8 KiB
C++
171 lines
7.8 KiB
C++
/********************************************************************
|
|
* 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"
|
|
#include "vtr_time.h"
|
|
|
|
/* Headers from openfpgashell library */
|
|
#include "command_exit_codes.h"
|
|
|
|
/* Headers from openfpgautil library */
|
|
#include "openfpga_digest.h"
|
|
|
|
#include "openfpga_reserved_words.h"
|
|
#include "openfpga_naming.h"
|
|
|
|
#include "mux_utils.h"
|
|
#include "circuit_library_utils.h"
|
|
|
|
#include "sdc_writer_naming.h"
|
|
#include "sdc_writer_utils.h"
|
|
|
|
#include "sdc_mux_utils.h"
|
|
|
|
/* begin namespace openfpga */
|
|
namespace openfpga {
|
|
|
|
/********************************************************************
|
|
* Break combinational loops in FPGA fabric, which mainly come from
|
|
* loops of multiplexers.
|
|
* To handle this, we disable the timing at outputs of routing multiplexers
|
|
*******************************************************************/
|
|
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 ModuleId& top_module) {
|
|
/* Create the file name for Verilog netlist */
|
|
std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_MUX_OUTPUTS_FILE_NAME));
|
|
|
|
/* Start time count */
|
|
std::string timer_message = std::string("Write SDC to disable routing multiplexer outputs for P&R flow '") + sdc_fname + std::string("'");
|
|
vtr::ScopedStartFinishTimer timer(timer_message);
|
|
|
|
/* Create the file stream */
|
|
std::fstream fp;
|
|
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
|
|
|
|
check_file_stream(sdc_fname.c_str(), fp);
|
|
|
|
/* Generate the descriptions*/
|
|
print_sdc_file_header(fp, std::string("Disable routing multiplexer outputs for PnR"));
|
|
|
|
/* Iterate over the MUX modules */
|
|
for (const MuxId& mux_id : mux_lib.muxes()) {
|
|
const CircuitModelId& mux_model = mux_lib.mux_circuit_model(mux_id);
|
|
|
|
/* Skip LUTs, we only care about multiplexers here */
|
|
if (CIRCUIT_MODEL_MUX != circuit_lib.model_type(mux_model)) {
|
|
continue;
|
|
}
|
|
|
|
const MuxGraph& mux_graph = mux_lib.mux_graph(mux_id);
|
|
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));
|
|
|
|
/* 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
|
|
*/
|
|
for (const BasicPort& output_port : module_manager.module_ports_by_type(mux_module, ModuleManager::MODULE_OUTPUT_PORT)) {
|
|
rec_print_sdc_disable_timing_for_module_ports(fp,
|
|
flatten_names,
|
|
module_manager,
|
|
top_module,
|
|
mux_module,
|
|
format_dir_path(module_manager.module_name(top_module)),
|
|
output_port.get_name());
|
|
}
|
|
}
|
|
|
|
/* Close file handler */
|
|
fp.close();
|
|
}
|
|
|
|
/********************************************************************
|
|
* Break combinational loops in FPGA fabric, which mainly come from
|
|
* loops of multiplexers.
|
|
* To handle this, we disable the timing at configuration ports of routing multiplexers
|
|
*
|
|
* Return code:
|
|
* 0: success
|
|
* 1: fatal error occurred
|
|
*******************************************************************/
|
|
int print_sdc_disable_routing_multiplexer_configure_ports(std::fstream& fp,
|
|
const bool& flatten_names,
|
|
const MuxLibrary& mux_lib,
|
|
const CircuitLibrary& circuit_lib,
|
|
const ModuleManager& module_manager,
|
|
const ModuleId& top_module) {
|
|
|
|
if (false == valid_file_stream(fp)) {
|
|
return CMD_EXEC_FATAL_ERROR;
|
|
}
|
|
|
|
/* Iterate over the MUX modules */
|
|
for (const MuxId& mux_id : mux_lib.muxes()) {
|
|
const CircuitModelId& mux_model = mux_lib.mux_circuit_model(mux_id);
|
|
|
|
/* Skip LUTs, we only care about multiplexers here */
|
|
if (CIRCUIT_MODEL_MUX != circuit_lib.model_type(mux_model)) {
|
|
continue;
|
|
}
|
|
|
|
const MuxGraph& mux_graph = mux_lib.mux_graph(mux_id);
|
|
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));
|
|
|
|
/* 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
|
|
*/
|
|
for (const CircuitPortId& mux_sram_port : find_circuit_regular_sram_ports(circuit_lib, mux_model)) {
|
|
const std::string& mux_sram_port_name = circuit_lib.port_lib_name(mux_sram_port);
|
|
VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, module_manager.find_module_port(mux_module, mux_sram_port_name)));
|
|
if (CMD_EXEC_FATAL_ERROR ==
|
|
rec_print_sdc_disable_timing_for_module_ports(fp,
|
|
flatten_names,
|
|
module_manager,
|
|
top_module,
|
|
mux_module,
|
|
format_dir_path(module_manager.module_name(top_module)),
|
|
mux_sram_port_name)) {
|
|
return CMD_EXEC_FATAL_ERROR;
|
|
}
|
|
|
|
const std::string& mux_sram_inv_port_name = circuit_lib.port_lib_name(mux_sram_port) + INV_PORT_POSTFIX;
|
|
VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, module_manager.find_module_port(mux_module, mux_sram_inv_port_name)));
|
|
if (CMD_EXEC_FATAL_ERROR ==
|
|
rec_print_sdc_disable_timing_for_module_ports(fp,
|
|
flatten_names,
|
|
module_manager,
|
|
top_module,
|
|
mux_module,
|
|
format_dir_path(module_manager.module_name(top_module)),
|
|
mux_sram_inv_port_name)) {
|
|
return CMD_EXEC_FATAL_ERROR;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return CMD_EXEC_SUCCESS;
|
|
}
|
|
|
|
} /* end namespace openfpga */
|