add options to use general-purpose wildcards in SDC generator
This commit is contained in:
parent
facd87dafe
commit
8695c5ee78
|
@ -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 */
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue