add options to use general-purpose wildcards in SDC generator

This commit is contained in:
tangxifan 2020-05-02 14:17:07 -06:00
parent facd87dafe
commit 8695c5ee78
14 changed files with 263 additions and 20 deletions

View File

@ -0,0 +1,105 @@
/************************************************************************
* Member functions for WildCardString class
***********************************************************************/
#include <cstring>
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "openfpga_wildcard_string.h"
/* namespace openfpga begins */
namespace openfpga {
/************************************************************************
* Constructors
***********************************************************************/
WildCardString::WildCardString(const std::string& data) {
set_data(data);
}
/************************************************************************
* Public Accessors
***********************************************************************/
std::string WildCardString::data() const {
return data_;
}
/************************************************************************
* Public Mutators
***********************************************************************/
void WildCardString::set_data(const std::string& data) {
data_ = data;
set_default_wildcard_char();
set_default_sensitive_chars();
apply_wildcard_char();
compress();
}
/************************************************************************
* Internal Mutators
***********************************************************************/
void WildCardString::set_default_wildcard_char() {
wildcard_char_ = '*';
}
void WildCardString::set_default_sensitive_chars() {
sensitive_chars_.clear();
sensitive_chars_.reserve(10);
sensitive_chars_.push_back('0');
sensitive_chars_.push_back('1');
sensitive_chars_.push_back('2');
sensitive_chars_.push_back('3');
sensitive_chars_.push_back('4');
sensitive_chars_.push_back('5');
sensitive_chars_.push_back('6');
sensitive_chars_.push_back('7');
sensitive_chars_.push_back('8');
sensitive_chars_.push_back('9');
}
void WildCardString::apply_wildcard_char() {
/* Step by step:
* For each sensitive character,
* replace all of its occurance in the string data_ with wildcard character
*/
for (const char& char_to_replace : sensitive_chars_) {
size_t cur_pos = 0;
std::string::size_type found;
while (std::string::npos != (found = data_.find_first_of(char_to_replace, cur_pos))) {
data_.replace(found, 1, 1, wildcard_char_);
cur_pos = found + 1;
}
}
}
void WildCardString::compress() {
for (std::string::size_type i = 0; i < data_.size(); ++i) {
/* Care only wildcard character */
if (wildcard_char_ != data_[i]) {
continue;
}
/* Finish if this is the end of string */
if (data_.size() - 1 == i) {
break;
}
/* Try to find the next element and see if the same as wild card
* Keep erase the next element until we have a non-wildcard character
*/
while (data_[i] == data_[i + 1]) {
/* Erase the next element */
data_.erase(i + 1, 1);
/* Finish if this is the end of string */
if (data_.size() - 1 == i) {
break;
}
}
}
}
} /* namespace openfpga ends */

View File

@ -0,0 +1,57 @@
#ifndef OPENFPGA_WILDCARD_STRING_H
#define OPENFPGA_WILDCARD_STRING_H
/********************************************************************
* Include header files that are required by data structure declaration
*******************************************************************/
#include <string>
#include <vector>
/* namespace openfpga begins */
namespace openfpga {
/************************************************************************
* This file includes a object that can apply wildcard characters
* By default it will replace any digital numbers with a '*' character
* Users can set the wildcard character on their needs
*
* Example:
* std::string orig_str;
* WildCardString wc_str(orig_str);
* std::string output = wc_str.data();
*
***********************************************************************/
class WildCardString {
public : /* Constructors*/
WildCardString (const std::string& data);
public : /* Public Accessors */
std::string data() const;
public : /* Public Mutators */
/* Give a string to apply wildcards */
void set_data(const std::string& data);
private : /* Private Mutators */
/* Use default wildcard character '*' */
void set_default_wildcard_char();
/* Use default sensitive words which are numbers */
void set_default_sensitive_chars();
/* Replace sensitive words with wildcard characters */
void apply_wildcard_char();
/* Remove redundant wildcard chars (which are next to each other) */
void compress();
private : /* Internal data */
std::string data_; /* Lines to be splited */
std::vector<char> sensitive_chars_;
char wildcard_char_;
};
} /* namespace openfpga ends */
#endif

View File

@ -30,6 +30,20 @@ std::string generate_instance_name(const std::string& instance_name,
return instance_name + std::string("_") + std::to_string(instance_id) + std::string("_");
}
/************************************************
* A generic function to generate the instance name
* in the following format:
* <instance_name>_<id>_
* This is mainly used by module manager to give a default
* name for each instance when outputting the module
* in Verilog/SPICE format
***********************************************/
std::string generate_instance_wildcard_name(const std::string& instance_name,
const std::string& wildcard_str) {
return instance_name + std::string("_") + wildcard_str + std::string("_");
}
/************************************************
* Generate the node name for a multiplexing structure
* Case 1 : If there is an intermediate buffer followed by,

View File

@ -26,6 +26,9 @@ namespace openfpga {
std::string generate_instance_name(const std::string& instance_name,
const size_t& instance_id);
std::string generate_instance_wildcard_name(const std::string& instance_name,
const std::string& wildcard_str);
std::string generate_mux_node_name(const size_t& node_level,
const bool& add_buffer_postfix);

View File

@ -29,6 +29,7 @@ int write_pnr_sdc(OpenfpgaContext& openfpga_ctx,
const Command& cmd, const CommandContext& cmd_context) {
CommandOptionId opt_output_dir = cmd.option("file");
CommandOptionId opt_flatten_names = cmd.option("flatten_names");
CommandOptionId opt_constrain_global_port = cmd.option("constrain_global_port");
CommandOptionId opt_constrain_non_clock_global_port = cmd.option("constrain_non_clock_global_port");
CommandOptionId opt_constrain_grid = cmd.option("constrain_grid");
@ -49,6 +50,7 @@ int write_pnr_sdc(OpenfpgaContext& openfpga_ctx,
PnrSdcOption options(sdc_dir_path);
options.set_flatten_names(cmd_context.option_enable(cmd, opt_flatten_names));
options.set_constrain_global_port(cmd_context.option_enable(cmd, opt_constrain_global_port));
options.set_constrain_non_clock_global_port(cmd_context.option_enable(cmd, opt_constrain_non_clock_global_port));
options.set_constrain_grid(cmd_context.option_enable(cmd, opt_constrain_grid));
@ -95,6 +97,7 @@ int write_analysis_sdc(OpenfpgaContext& openfpga_ctx,
const Command& cmd, const CommandContext& cmd_context) {
CommandOptionId opt_output_dir = cmd.option("file");
CommandOptionId opt_flatten_names = cmd.option("flatten_names");
/* This is an intermediate data structure which is designed to modularize the FPGA-SDC
* Keep it independent from any other outside data structures
@ -106,6 +109,7 @@ int write_analysis_sdc(OpenfpgaContext& openfpga_ctx,
AnalysisSdcOption options(sdc_dir_path);
options.set_generate_sdc_analysis(true);
options.set_flatten_names(cmd_context.option_enable(cmd, opt_flatten_names));
/* Collect global ports from the circuit library:
* TODO: should we place this in the OpenFPGA context?

View File

@ -26,6 +26,9 @@ ShellCommandId add_openfpga_write_pnr_sdc_command(openfpga::Shell<OpenfpgaContex
shell_cmd.set_option_short_name(output_opt, "f");
shell_cmd.set_option_require_value(output_opt, openfpga::OPT_STRING);
/* Add an option '--flatten_name' */
shell_cmd.add_option("flatten_names", false, "Use flatten names to compress SDC file size");
/* Add an option '--constrain_global_port' */
shell_cmd.add_option("constrain_global_port", false, "Constrain all the global ports of FPGA fabric");
@ -85,6 +88,9 @@ ShellCommandId add_openfpga_write_analysis_sdc_command(openfpga::Shell<OpenfpgaC
/* Add an option '--verbose' */
shell_cmd.add_option("verbose", false, "Enable verbose output");
/* Add an option '--flatten_name' */
shell_cmd.add_option("flatten_names", false, "Use flatten names to compress SDC file size");
/* Add command 'write_fabric_verilog' to the Shell */
ShellCommandId shell_cmd_id = shell.add_command(shell_cmd, "generate SDC files for timing analysis a PnRed FPGA fabric mapped by a benchmark");

View File

@ -11,6 +11,7 @@ namespace openfpga {
********************************************************************/
AnalysisSdcOption::AnalysisSdcOption(const std::string& sdc_dir) {
sdc_dir_ = sdc_dir;
flatten_names_ = false;
generate_sdc_analysis_ = false;
}
@ -21,6 +22,10 @@ std::string AnalysisSdcOption::sdc_dir() const {
return sdc_dir_;
}
bool AnalysisSdcOption::flatten_names() const {
return flatten_names_;
}
bool AnalysisSdcOption::generate_sdc_analysis() const {
return generate_sdc_analysis_;
}
@ -32,6 +37,10 @@ void AnalysisSdcOption::set_sdc_dir(const std::string& sdc_dir) {
sdc_dir_ = sdc_dir;
}
void AnalysisSdcOption::set_flatten_names(const bool& flatten_names) {
flatten_names_ = flatten_names;
}
void AnalysisSdcOption::set_generate_sdc_analysis(const bool& generate_sdc_analysis) {
generate_sdc_analysis_ = generate_sdc_analysis;
}

View File

@ -16,13 +16,16 @@ class AnalysisSdcOption {
AnalysisSdcOption(const std::string& sdc_dir);
public: /* Public accessors */
std::string sdc_dir() const;
bool flatten_names() const;
bool generate_sdc_analysis() const;
public: /* Public mutators */
void set_sdc_dir(const std::string& sdc_dir);
void set_flatten_names(const bool& flatten_names);
void set_generate_sdc_analysis(const bool& generate_sdc_analysis);
private: /* Internal data */
std::string sdc_dir_;
bool generate_sdc_analysis_;
bool flatten_names_;
};
} /* end namespace openfpga */

View File

@ -264,7 +264,7 @@ void print_analysis_sdc(const AnalysisSdcOption& option,
openfpga_ctx.arch().circuit_lib, global_ports);
/* Disable the timing for configuration cells */
rec_print_pnr_sdc_disable_configurable_memory_module_output(fp,
rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, option.flatten_names(),
openfpga_ctx.module_graph(), top_module,
format_dir_path(openfpga_ctx.module_graph().module_name(top_module)));

View File

@ -11,6 +11,7 @@ namespace openfpga {
********************************************************************/
PnrSdcOption::PnrSdcOption(const std::string& sdc_dir) {
sdc_dir_ = sdc_dir;
flatten_names_ = false;
constrain_global_port_ = false;
constrain_non_clock_global_port_ = false;
constrain_grid_ = false;
@ -29,6 +30,10 @@ std::string PnrSdcOption::sdc_dir() const {
return sdc_dir_;
}
bool PnrSdcOption::flatten_names() const {
return flatten_names_;
}
bool PnrSdcOption::generate_sdc_pnr() const {
return constrain_global_port_
|| constrain_grid_
@ -82,6 +87,10 @@ void PnrSdcOption::set_sdc_dir(const std::string& sdc_dir) {
sdc_dir_ = sdc_dir;
}
void PnrSdcOption::set_flatten_names(const bool& flatten_names) {
flatten_names_ = flatten_names;
}
void PnrSdcOption::set_generate_sdc_pnr(const bool& generate_sdc_pnr) {
constrain_global_port_ = generate_sdc_pnr;
constrain_grid_ = generate_sdc_pnr;

View File

@ -16,6 +16,7 @@ class PnrSdcOption {
PnrSdcOption(const std::string& sdc_dir);
public: /* Public accessors */
std::string sdc_dir() const;
bool flatten_names() const;
bool generate_sdc_pnr() const;
bool constrain_global_port() const;
bool constrain_non_clock_global_port() const;
@ -28,6 +29,7 @@ class PnrSdcOption {
bool constrain_zero_delay_paths() const;
public: /* Public mutators */
void set_sdc_dir(const std::string& sdc_dir);
void set_flatten_names(const bool& flatten_names);
void set_generate_sdc_pnr(const bool& generate_sdc_pnr);
void set_constrain_global_port(const bool& constrain_global_port);
void set_constrain_non_clock_global_port(const bool& constrain_non_clock_global_port);
@ -40,6 +42,7 @@ class PnrSdcOption {
void set_constrain_zero_delay_paths(const bool& constrain_zero_delay_paths);
private: /* Internal data */
std::string sdc_dir_;
bool flatten_names_;
bool constrain_global_port_;
bool constrain_non_clock_global_port_;
bool constrain_grid_;

View File

@ -43,6 +43,7 @@ namespace openfpga {
*******************************************************************/
static
void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_dir,
const bool& flatten_names,
const ModuleManager& module_manager,
const ModuleId& top_module) {
@ -63,7 +64,8 @@ void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_
print_sdc_file_header(fp, std::string("Disable configurable memory outputs for PnR"));
/* Go recursively in the module manager, starting from the top-level module: instance id of the top-level module is 0 by default */
rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, module_manager, top_module,
rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, flatten_names,
module_manager, top_module,
format_dir_path(module_manager.module_name(top_module)));
/* Close file handler */
@ -266,7 +268,7 @@ 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(), 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 */

View File

@ -5,10 +5,14 @@
/* 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_memory_utils.h"
@ -23,42 +27,65 @@ namespace openfpga {
* 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_configurable_memory_module_output(std::fstream& fp,
const bool& flatten_names,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& parent_module_path) {
/* Keep tracking multiple-instanced-blocks (MIB)
* if they should be skipped as the unique module has been visited already
/* 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<ModuleId, bool> skip_mib;
std::map<ModuleId, std::vector<std::string>> wildcard_names;
/* For each configurable child, we will go one level down in priority */
for (size_t child_index = 0; child_index < module_manager.configurable_children(parent_module).size(); ++child_index) {
std::string child_module_path = parent_module_path;
ModuleId child_module_id = module_manager.configurable_children(parent_module)[child_index];
size_t child_instance_id = module_manager.configurable_child_instances(parent_module)[child_index];
std::string child_instance_name;
if (true == module_manager.instance_name(parent_module, child_module_id, child_instance_id).empty()) {
if (0 < skip_mib.count(child_module_id)) {
VTR_ASSERT(skip_mib.at(child_module_id) = true);
child_instance_name = generate_instance_name(module_manager.module_name(child_module_id), child_instance_id);
} else {
child_instance_name = module_manager.instance_name(parent_module, child_module_id, child_instance_id);
}
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_id))
&& (wildcard_names.at(child_module_id).end() != std::find(wildcard_names.at(child_module_id).begin(),
wildcard_names.at(child_module_id).end(),
wildcard_str.data())) ) {
continue;
}
/* Give a default name <module_name>_<instance_id>_ */
child_module_path += module_manager.module_name(child_module_id);
child_module_path += "_";
child_module_path += "*";
//child_module_path += std::to_string(child_instance_id);
child_module_path += "_";
/* If we use wild card to disable all the other instance
* So we can skip later if there is no specific instance name
*/
skip_mib[child_module_id] = true;
child_module_path += wildcard_str.data();
wildcard_names[child_module_id].push_back(wildcard_str.data());
} else {
child_module_path += module_manager.instance_name(parent_module, child_module_id, child_instance_id);
child_module_path += child_instance_name;
}
child_module_path = format_dir_path(child_module_path);
rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, module_manager,
rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, flatten_names,
module_manager,
child_module_id,
child_module_path);
}

View File

@ -16,6 +16,7 @@
namespace openfpga {
void rec_print_pnr_sdc_disable_configurable_memory_module_output(std::fstream& fp,
const bool& flatten_names,
const ModuleManager& module_manager,
const ModuleId& parent_module,
const std::string& parent_module_path);