add configuration chain sdc writer
This commit is contained in:
parent
dad99d13a2
commit
4c0953415b
|
@ -15,6 +15,7 @@
|
|||
#include "circuit_library_utils.h"
|
||||
#include "pnr_sdc_writer.h"
|
||||
#include "analysis_sdc_writer.h"
|
||||
#include "configuration_chain_sdc_writer.h"
|
||||
#include "openfpga_sdc.h"
|
||||
|
||||
/* Include global variables of VPR */
|
||||
|
@ -102,6 +103,41 @@ int write_pnr_sdc(OpenfpgaContext& openfpga_ctx,
|
|||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A wrapper function to call the PnR SDC generator on configuration chain
|
||||
* of FPGA-SDC
|
||||
*******************************************************************/
|
||||
int write_configuration_chain_sdc(const OpenfpgaContext& openfpga_ctx,
|
||||
const Command& cmd, const CommandContext& cmd_context) {
|
||||
/* If the configuration protocol is not a configuration chain, we will not write anything */
|
||||
if (CONFIG_MEM_SCAN_CHAIN != openfpga_ctx.arch().config_protocol.type()) {
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Configuration protocol is %s. Expected %s to write SDC!\n",
|
||||
CONFIG_PROTOCOL_TYPE_STRING[openfpga_ctx.arch().config_protocol.type()],
|
||||
CONFIG_PROTOCOL_TYPE_STRING[CONFIG_MEM_SCAN_CHAIN]);
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* Get command options */
|
||||
CommandOptionId opt_output_dir = cmd.option("file");
|
||||
CommandOptionId opt_time_unit = cmd.option("time_unit");
|
||||
CommandOptionId opt_min_delay = cmd.option("min_delay");
|
||||
CommandOptionId opt_max_delay = cmd.option("max_delay");
|
||||
|
||||
std::string sdc_dir_path = format_dir_path(cmd_context.option_value(cmd, opt_output_dir));
|
||||
|
||||
float time_unit = string_to_time_unit(cmd_context.option_value(cmd, opt_time_unit));
|
||||
|
||||
/* Write the SDC for configuration chain */
|
||||
print_pnr_sdc_constrain_configurable_chain(cmd_context.option_value(cmd, opt_output_dir),
|
||||
time_unit,
|
||||
std::stof(cmd_context.option_value(cmd, opt_max_delay)),
|
||||
std::stof(cmd_context.option_value(cmd, opt_min_delay)),
|
||||
openfpga_ctx.module_graph());
|
||||
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A wrapper function to call the analysis SDC generator of FPGA-SDC
|
||||
*******************************************************************/
|
||||
|
|
|
@ -18,6 +18,9 @@ namespace openfpga {
|
|||
int write_pnr_sdc(OpenfpgaContext& openfpga_ctx,
|
||||
const Command& cmd, const CommandContext& cmd_context);
|
||||
|
||||
int write_configuration_chain_sdc(const OpenfpgaContext& openfpga_ctx,
|
||||
const Command& cmd, const CommandContext& cmd_context);
|
||||
|
||||
int write_analysis_sdc(OpenfpgaContext& openfpga_ctx,
|
||||
const Command& cmd, const CommandContext& cmd_context);
|
||||
|
||||
|
|
|
@ -80,6 +80,45 @@ ShellCommandId add_openfpga_write_pnr_sdc_command(openfpga::Shell<OpenfpgaContex
|
|||
return shell_cmd_id;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* - Add a command to Shell environment: generate PnR SDC for configuration chain
|
||||
* - Add associated options
|
||||
* - Add command dependency
|
||||
*******************************************************************/
|
||||
static
|
||||
ShellCommandId add_openfpga_write_configuration_chain_sdc_command(openfpga::Shell<OpenfpgaContext>& shell,
|
||||
const ShellCommandClassId& cmd_class_id,
|
||||
const std::vector<ShellCommandId>& dependent_cmds) {
|
||||
Command shell_cmd("write_configuration_chain_sdc");
|
||||
|
||||
/* Add an option '--file' in short '-f'*/
|
||||
CommandOptionId output_opt = shell_cmd.add_option("file", true, "Specify the SDC file to constrain configuration chain");
|
||||
shell_cmd.set_option_short_name(output_opt, "f");
|
||||
shell_cmd.set_option_require_value(output_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--time_unit' */
|
||||
CommandOptionId time_unit_opt = shell_cmd.add_option("time_unit", false, "Specify the time unit in SDC files. Acceptable is [a|f|p|n|u|m|k|M]s");
|
||||
shell_cmd.set_option_require_value(time_unit_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--min_delay' */
|
||||
CommandOptionId min_dly_opt = shell_cmd.add_option("min_delay", false, "Specify the minimum delay to be used.");
|
||||
shell_cmd.set_option_require_value(min_dly_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--max_delay' */
|
||||
CommandOptionId max_dly_opt = shell_cmd.add_option("max_delay", false, "Specify the maximum delay to be used.");
|
||||
shell_cmd.set_option_require_value(max_dly_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* Add command 'write_configuration_chain_sdc' to the Shell */
|
||||
ShellCommandId shell_cmd_id = shell.add_command(shell_cmd, "generate SDC files to constrain the configuration chain for FPGA fabric");
|
||||
shell.set_command_class(shell_cmd_id, cmd_class_id);
|
||||
shell.set_command_const_execute_function(shell_cmd_id, write_configuration_chain_sdc);
|
||||
|
||||
/* Add command dependency to the Shell */
|
||||
shell.set_command_dependency(shell_cmd_id, dependent_cmds);
|
||||
|
||||
return shell_cmd_id;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* - Add a command to Shell environment: generate PnR SDC
|
||||
* - Add associated options
|
||||
|
@ -134,6 +173,16 @@ void add_openfpga_sdc_commands(openfpga::Shell<OpenfpgaContext>& shell) {
|
|||
openfpga_sdc_cmd_class,
|
||||
pnr_sdc_cmd_dependency);
|
||||
|
||||
/********************************
|
||||
* Command 'write_configuration_chain_sdc'
|
||||
*/
|
||||
/* The 'write_configuration_chain_sdc' command should NOT be executed before 'build_fabric' */
|
||||
std::vector<ShellCommandId> cc_sdc_cmd_dependency;
|
||||
cc_sdc_cmd_dependency.push_back(build_fabric_id);
|
||||
add_openfpga_write_configuration_chain_sdc_command(shell,
|
||||
openfpga_sdc_cmd_class,
|
||||
cc_sdc_cmd_dependency);
|
||||
|
||||
/********************************
|
||||
* Command 'write_analysis_sdc'
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/********************************************************************
|
||||
* This file includes functions that print SDC (Synopsys Design Constraint)
|
||||
* files in physical design tools, i.e., Place & Route (PnR) tools
|
||||
* The SDC files are used to constrain the timing of configuration chain
|
||||
*
|
||||
* Note that this is different from the SDC to constrain VPR Place&Route
|
||||
* engine! These SDCs are designed for PnR to generate FPGA layouts!!!
|
||||
*******************************************************************/
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_time.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_scale.h"
|
||||
#include "openfpga_port.h"
|
||||
#include "openfpga_digest.h"
|
||||
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
#include "sdc_writer_utils.h"
|
||||
#include "configuration_chain_sdc_writer.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* Print SDC commands to constrain the timing between outputs and inputs
|
||||
* of all the configurable memory modules
|
||||
*
|
||||
* |<------Max/Min delay-->|
|
||||
* | |
|
||||
* +------+ out in +------+
|
||||
* | CCFF |---------------------->| CCFF |
|
||||
* +------+ +------+
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_print_pnr_sdc_constrain_configurable_chain(std::fstream& fp,
|
||||
const float& tmax,
|
||||
const float& tmin,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const std::string& parent_module_path,
|
||||
std::string& previous_module_path,
|
||||
ModuleId& previous_module) {
|
||||
|
||||
/* 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()) {
|
||||
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);
|
||||
}
|
||||
|
||||
child_module_path += child_instance_name;
|
||||
|
||||
child_module_path = format_dir_path(child_module_path);
|
||||
|
||||
rec_print_pnr_sdc_constrain_configurable_chain(fp,
|
||||
tmax, tmin,
|
||||
module_manager,
|
||||
child_module_id,
|
||||
child_module_path,
|
||||
previous_module_path,
|
||||
previous_module);
|
||||
}
|
||||
|
||||
/* If there is no configurable children any more, this is a leaf module, print a SDC command for disable timing */
|
||||
if (0 < module_manager.configurable_children(parent_module).size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Validate file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* Disable timing for each output port of this module */
|
||||
if (!previous_module_path.empty()) {
|
||||
bool first_port = true;
|
||||
for (const BasicPort& output_port : module_manager.module_ports_by_type(previous_module, ModuleManager::MODULE_OUTPUT_PORT)) {
|
||||
/* Only the first output port will be considered,
|
||||
* being consistent with build_memory_module.cpp:395
|
||||
*/
|
||||
if (false == first_port) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const BasicPort& input_port : module_manager.module_ports_by_type(parent_module, ModuleManager::MODULE_INPUT_PORT)) {
|
||||
print_pnr_sdc_constrain_max_delay(fp,
|
||||
previous_module_path,
|
||||
generate_sdc_port(output_port),
|
||||
parent_module_path,
|
||||
generate_sdc_port(input_port),
|
||||
tmax);
|
||||
|
||||
print_pnr_sdc_constrain_min_delay(fp,
|
||||
previous_module_path,
|
||||
generate_sdc_port(output_port),
|
||||
parent_module_path,
|
||||
generate_sdc_port(input_port),
|
||||
tmin);
|
||||
}
|
||||
|
||||
first_port = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update previous module */
|
||||
previous_module_path = parent_module_path;
|
||||
previous_module = parent_module;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Break combinational loops in FPGA fabric, which mainly come from
|
||||
* configurable memory cells.
|
||||
* To handle this, we disable the outputs of memory cells
|
||||
*******************************************************************/
|
||||
void print_pnr_sdc_constrain_configurable_chain(const std::string& sdc_fname,
|
||||
const float& time_unit,
|
||||
const float& max_delay,
|
||||
const float& min_delay,
|
||||
const ModuleManager& module_manager) {
|
||||
|
||||
/* Create the directory */
|
||||
create_directory(find_path_dir_name(sdc_fname));
|
||||
|
||||
/* Start time count */
|
||||
std::string timer_message = std::string("Write SDC to constrain configurable chain 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("Timing constraints for configurable chains used in PnR"));
|
||||
|
||||
/* Print time unit for the SDC file */
|
||||
print_sdc_timescale(fp, time_unit_to_string(time_unit));
|
||||
|
||||
std::string top_module_name = generate_fpga_top_module_name();
|
||||
ModuleId top_module = module_manager.find_module(top_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
|
||||
|
||||
/* Go recursively in the module manager, starting from the top-level module: instance id of the top-level module is 0 by default */
|
||||
std::string previous_module_path;
|
||||
ModuleId previous_module = ModuleId::INVALID();
|
||||
rec_print_pnr_sdc_constrain_configurable_chain(fp,
|
||||
max_delay/time_unit, min_delay/time_unit,
|
||||
module_manager, top_module,
|
||||
format_dir_path(module_manager.module_name(top_module)),
|
||||
previous_module_path,
|
||||
previous_module);
|
||||
|
||||
/* Close file handler */
|
||||
fp.close();
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef CONFIGURATION_CHAIN_SDC_WRITER_H
|
||||
#define CONFIGURATION_CHAIN_SDC_WRITER_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "module_manager.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void print_pnr_sdc_constrain_configurable_chain(const std::string& sdc_fname,
|
||||
const float& time_unit,
|
||||
const float& max_delay,
|
||||
const float& min_delay,
|
||||
const ModuleManager& module_manager);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -95,14 +95,14 @@ void print_pnr_sdc_constrain_max_delay(std::fstream& fp,
|
|||
|
||||
fp << " -from ";
|
||||
if (!src_instance_name.empty()) {
|
||||
fp << src_instance_name << "/";
|
||||
fp << format_dir_path(src_instance_name);
|
||||
}
|
||||
fp << src_port_name;
|
||||
|
||||
fp << " -to ";
|
||||
|
||||
if (!des_instance_name.empty()) {
|
||||
fp << des_instance_name << "/";
|
||||
fp << format_dir_path(des_instance_name);
|
||||
}
|
||||
fp << des_port_name;
|
||||
|
||||
|
@ -130,7 +130,7 @@ void print_pnr_sdc_regexp_constrain_max_delay(std::fstream& fp,
|
|||
fp << " -from ";
|
||||
fp << "[get_pins -regexp \"";
|
||||
if (!src_instance_name.empty()) {
|
||||
fp << src_instance_name << "/";
|
||||
fp << format_dir_path(src_instance_name);
|
||||
}
|
||||
fp << src_port_name;
|
||||
|
||||
|
@ -140,7 +140,7 @@ void print_pnr_sdc_regexp_constrain_max_delay(std::fstream& fp,
|
|||
fp << "[get_pins -regexp \"";
|
||||
|
||||
if (!des_instance_name.empty()) {
|
||||
fp << des_instance_name << "/";
|
||||
fp << format_dir_path(des_instance_name);
|
||||
}
|
||||
fp << des_port_name;
|
||||
|
||||
|
@ -167,14 +167,14 @@ void print_pnr_sdc_constrain_min_delay(std::fstream& fp,
|
|||
|
||||
fp << " -from ";
|
||||
if (!src_instance_name.empty()) {
|
||||
fp << src_instance_name << "/";
|
||||
fp << format_dir_path(src_instance_name);
|
||||
}
|
||||
fp << src_port_name;
|
||||
|
||||
fp << " -to ";
|
||||
|
||||
if (!des_instance_name.empty()) {
|
||||
fp << des_instance_name << "/";
|
||||
fp << format_dir_path(des_instance_name);
|
||||
}
|
||||
fp << des_port_name;
|
||||
|
||||
|
|
Loading…
Reference in New Issue