diff --git a/openfpga/src/base/openfpga_sdc_command.cpp b/openfpga/src/base/openfpga_sdc_command.cpp index 02595a10c..77c581da2 100644 --- a/openfpga/src/base/openfpga_sdc_command.cpp +++ b/openfpga/src/base/openfpga_sdc_command.cpp @@ -27,7 +27,7 @@ ShellCommandId add_openfpga_write_pnr_sdc_command(openfpga::Shell sb_range = device_rr_gsb.get_gsb_range(); - /* Go for each SB */ - for (size_t ix = 0; ix < sb_range.x(); ++ix) { - for (size_t iy = 0; iy < sb_range.y(); ++iy) { - const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy); - - if (false == rr_gsb.is_sb_exist()) { - continue; - } - - vtr::Point gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); - std::string sb_instance_name = generate_switch_block_module_name(gsb_coordinate); - - ModuleId sb_module = module_manager.find_module(sb_instance_name); - VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); - - /* Disable the outputs of the module */ - for (const BasicPort& output_port : module_manager.module_ports_by_type(sb_module, ModuleManager::MODULE_OUTPUT_PORT)) { - fp << "set_disable_timing " << sb_instance_name << "/" << output_port.get_name() << std::endl; - fp << std::endl; - } - } - } - - /* 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 outputs of Switch blocks - * This function is designed for compact routing hierarchy - *******************************************************************/ -static -void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::string& sdc_dir, + const bool& flatten_names, const ModuleManager& module_manager, const ModuleId& top_module, const DeviceRRGSB& device_rr_gsb) { @@ -209,6 +156,131 @@ void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::strin /* Generate the descriptions*/ print_sdc_file_header(fp, std::string("Disable Switch Block outputs for PnR")); + std::string root_path = format_dir_path(module_manager.module_name(top_module)); + + /* 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; + + /* Get the range of SB array */ + vtr::Point sb_range = device_rr_gsb.get_gsb_range(); + /* Go for each SB */ + for (size_t ix = 0; ix < sb_range.x(); ++ix) { + for (size_t iy = 0; iy < sb_range.y(); ++iy) { + const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy); + + if (false == rr_gsb.is_sb_exist()) { + continue; + } + + std::string module_path = root_path; + + vtr::Point gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); + std::string sb_instance_name = generate_switch_block_module_name(gsb_coordinate); + + ModuleId sb_module = module_manager.find_module(sb_instance_name); + VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); + + if (false == flatten_names) { + /* Try to adapt to a wildcard name: replace all the numbers with a wildcard character '*' */ + WildCardString wildcard_str(sb_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(sb_module)) + && (wildcard_names.at(sb_module).end() != std::find(wildcard_names.at(sb_module).begin(), + wildcard_names.at(sb_module).end(), + wildcard_str.data())) ) { + continue; + } + + module_path += wildcard_str.data(); + + wildcard_names[sb_module].push_back(wildcard_str.data()); + } else { + module_path += sb_instance_name; + } + + module_path = format_dir_path(module_path); + + std::vector port_wildcard_names; + + /* Disable the outputs of the module */ + for (const BasicPort& output_port : module_manager.module_ports_by_type(sb_module, ModuleManager::MODULE_OUTPUT_PORT)) { + std::string port_name = output_port.get_name(); + + if (false == flatten_names) { + /* Try to adapt to a wildcard name: replace all the numbers with a wildcard character '*' */ + WildCardString port_wildcard_str(output_port.get_name()); + /* If the wildcard name is already in the list, we can skip this + * Otherwise, we have to + * - output this port + * - record the wildcard name in the vector + */ + if (port_wildcard_names.end() != std::find(port_wildcard_names.begin(), + port_wildcard_names.end(), + port_wildcard_str.data())) { + continue; + } + + port_name = port_wildcard_str.data(); + + port_wildcard_names.push_back(port_wildcard_str.data()); + } + + fp << "set_disable_timing "; + fp << module_path; + fp << port_name << std::endl; + + fp << std::endl; + } + } + } + + /* 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 outputs of Switch blocks + * This function is designed for compact routing hierarchy + *******************************************************************/ +static +void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::string& sdc_dir, + const bool& flatten_names, + const ModuleManager& module_manager, + const ModuleId& top_module, + const DeviceRRGSB& device_rr_gsb) { + /* Create the file name for Verilog netlist */ + std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_SB_OUTPUTS_FILE_NAME)); + + /* Start time count */ + std::string timer_message = std::string("Write SDC to disable switch block 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 Switch Block outputs for PnR")); + + std::string root_path = format_dir_path(module_manager.module_name(top_module)); + + /* 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; + /* Build unique switch block modules */ for (size_t isb = 0; isb < device_rr_gsb.get_num_sb_unique_module(); ++isb) { const RRGSB& rr_gsb = device_rr_gsb.get_sb_unique_module(isb); @@ -217,13 +289,66 @@ void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::strin ModuleId sb_module = module_manager.find_module(sb_module_name); VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); + + std::string module_path = root_path; /* Find all the instances in the top-level module */ for (const size_t& instance_id : module_manager.child_module_instances(top_module, sb_module)) { std::string sb_instance_name = module_manager.instance_name(top_module, sb_module, instance_id); + + if (false == flatten_names) { + /* Try to adapt to a wildcard name: replace all the numbers with a wildcard character '*' */ + WildCardString wildcard_str(sb_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(sb_module)) + && (wildcard_names.at(sb_module).end() != std::find(wildcard_names.at(sb_module).begin(), + wildcard_names.at(sb_module).end(), + wildcard_str.data())) ) { + continue; + } + + module_path += wildcard_str.data(); + + wildcard_names[sb_module].push_back(wildcard_str.data()); + } else { + module_path += sb_instance_name; + } + + module_path = format_dir_path(module_path); + + std::vector port_wildcard_names; + /* Disable the outputs of the module */ for (const BasicPort& output_port : module_manager.module_ports_by_type(sb_module, ModuleManager::MODULE_OUTPUT_PORT)) { - fp << "set_disable_timing " << sb_instance_name << "/" << output_port.get_name() << std::endl; + std::string port_name = output_port.get_name(); + + if (false == flatten_names) { + /* Try to adapt to a wildcard name: replace all the numbers with a wildcard character '*' */ + WildCardString port_wildcard_str(output_port.get_name()); + /* If the wildcard name is already in the list, we can skip this + * Otherwise, we have to + * - output this port + * - record the wildcard name in the vector + */ + if (port_wildcard_names.end() != std::find(port_wildcard_names.begin(), + port_wildcard_names.end(), + port_wildcard_str.data())) { + continue; + } + + port_name = port_wildcard_str.data(); + + port_wildcard_names.push_back(port_wildcard_str.data()); + } + + fp << "set_disable_timing "; + fp << module_path; + fp << port_name << std::endl; + fp << std::endl; } } @@ -282,12 +407,14 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options, if (true == sdc_options.constrain_switch_block_outputs()) { if (true == compact_routing_hierarchy) { print_pnr_sdc_compact_routing_disable_switch_block_outputs(sdc_options.sdc_dir(), + sdc_options.flatten_names(), module_manager, top_module, device_rr_gsb); } else { VTR_ASSERT_SAFE (false == compact_routing_hierarchy); print_pnr_sdc_flatten_routing_disable_switch_block_outputs(sdc_options.sdc_dir(), - module_manager, + sdc_options.flatten_names(), + module_manager, top_module, device_rr_gsb); } }