add time unit support on SDC generator. Now users can define time_unit thru cmd-line options
This commit is contained in:
parent
47f040822f
commit
8726c618eb
|
@ -0,0 +1,183 @@
|
|||
/********************************************************************
|
||||
* This file includes functions that convert time/resistance/capacitance
|
||||
* units to string or vice versa
|
||||
*******************************************************************/
|
||||
#include <cmath>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_scale.h"
|
||||
|
||||
namespace openfpga {
|
||||
|
||||
/* A small ratio for float number comparison
|
||||
* If the float number B is in the range of the referance A +/- epsilon
|
||||
* we regard A == B
|
||||
* A - A * EPSILON <= B <= A + A * EPSILON
|
||||
*/
|
||||
#define EPSILON_RATIO 1e-3
|
||||
|
||||
bool same_float_number(const float& a,
|
||||
const float& b,
|
||||
const float& epsilon) {
|
||||
/* Always use a positive epsilon */
|
||||
if ( (a - a * std::abs(epsilon) <= b)
|
||||
&& (b <= a + a * std::abs(epsilon)) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Convert numeric unit to string:
|
||||
* - 1e12 -> T
|
||||
* - 1e9 -> B
|
||||
* - 1e6 -> M
|
||||
* - 1e3 -> k
|
||||
* - 1. ->
|
||||
* - 1e-3 -> m
|
||||
* - 1e-6 -> u
|
||||
* - 1e-9 -> n
|
||||
* - 1e-12 -> p
|
||||
* - 1e-15 -> f
|
||||
* - 1e-18 -> a
|
||||
*******************************************************************/
|
||||
std::string unit_to_string(const float& unit) {
|
||||
if (true == same_float_number(unit, 1., EPSILON_RATIO)) {
|
||||
return std::string();
|
||||
/* Larger than 1 unit */
|
||||
} else if (true == same_float_number(unit, 1e3, EPSILON_RATIO)) {
|
||||
return std::string("k");
|
||||
} else if (true == same_float_number(unit, 1e6, EPSILON_RATIO)) {
|
||||
return std::string("M");
|
||||
} else if (true == same_float_number(unit, 1e9, EPSILON_RATIO)) {
|
||||
return std::string("B");
|
||||
} else if (true == same_float_number(unit, 1e12, EPSILON_RATIO)) {
|
||||
return std::string("T");
|
||||
/* Less than 1 unit */
|
||||
} else if (true == same_float_number(unit, 1e-3, EPSILON_RATIO)) {
|
||||
return std::string("m");
|
||||
} else if (true == same_float_number(unit, 1e-6, EPSILON_RATIO)) {
|
||||
return std::string("u");
|
||||
} else if (true == same_float_number(unit, 1e-9, EPSILON_RATIO)) {
|
||||
return std::string("n");
|
||||
} else if (true == same_float_number(unit, 1e-12, EPSILON_RATIO)) {
|
||||
return std::string("p");
|
||||
} else if (true == same_float_number(unit, 1e-15, EPSILON_RATIO)) {
|
||||
return std::string("f");
|
||||
} else if (true == same_float_number(unit, 1e-18, EPSILON_RATIO)) {
|
||||
return std::string("a");
|
||||
}
|
||||
|
||||
/* Invalid unit report error */
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid unit %g!\nAcceptable units are [1e12|1e9|1e6|1e3|1|1e-3|1e-6|1e-9|1e-12|1e-15|1e-18]\n",
|
||||
unit);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Convert numeric time unit to string
|
||||
* e.g. 1e-12 -> ps
|
||||
*******************************************************************/
|
||||
std::string time_unit_to_string(const float& unit) {
|
||||
/* For larger than 1 unit, we do not accept */
|
||||
if (1e6 < unit) {
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid time unit %g!\nAcceptable units are [1e6|1e3|1|1e-3|1e-6|1e-9|1e-12|1e-15|1e-18]\n",
|
||||
unit);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return unit_to_string(unit) + std::string("s");
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Convert string unit to numeric:
|
||||
* - T -> 1e12
|
||||
* - B -> 1e9
|
||||
* - M -> 1e6
|
||||
* - k -> 1e3
|
||||
* - "" -> 1.
|
||||
* - m -> 1e-3
|
||||
* - u -> 1e-6
|
||||
* - n -> 1e-9
|
||||
* - p -> 1e-12
|
||||
* - f -> 1e-15
|
||||
* - a -> 1e-18
|
||||
*******************************************************************/
|
||||
float string_to_unit(const std::string& scale) {
|
||||
if (true == scale.empty()) {
|
||||
return 1.;
|
||||
/* Larger than 1 unit */
|
||||
} else if (std::string("T") == scale) {
|
||||
return 1e12;
|
||||
} else if (std::string("B") == scale) {
|
||||
return 1e9;
|
||||
} else if (std::string("M") == scale) {
|
||||
return 1e6;
|
||||
} else if (std::string("k") == scale) {
|
||||
return 1e3;
|
||||
/* Less than 1 unit */
|
||||
} else if (std::string("m") == scale) {
|
||||
return 1e-3;
|
||||
} else if (std::string("u") == scale) {
|
||||
return 1e-6;
|
||||
} else if (std::string("n") == scale) {
|
||||
return 1e-9;
|
||||
} else if (std::string("p") == scale) {
|
||||
return 1e-12;
|
||||
} else if (std::string("f") == scale) {
|
||||
return 1e-15;
|
||||
} else if (std::string("a") == scale) {
|
||||
return 1e-18;
|
||||
}
|
||||
|
||||
/* Invalid unit report error */
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid unit %s!\nAcceptable units are [a|f|p|n|u|k|M|B|T] or empty\n",
|
||||
scale);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Convert string time unit to numeric
|
||||
* e.g. ps -> 1e-12
|
||||
*******************************************************************/
|
||||
float string_to_time_unit(const std::string& scale) {
|
||||
if ( (1 != scale.length())
|
||||
&& (2 != scale.length()) ) {
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Time unit (='%s') must contain only one or two characters!\n",
|
||||
scale);
|
||||
}
|
||||
/* The last character must be 's' */
|
||||
if ('s' != scale.back()) {
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Time unit (='%s') must end with 's'!\n",
|
||||
scale);
|
||||
}
|
||||
|
||||
float unit = 1.;
|
||||
VTR_ASSERT ( (1 == scale.length())
|
||||
|| (2 == scale.length()) );
|
||||
if (2 == scale.length()) {
|
||||
unit = string_to_unit(scale.substr(0, 1));
|
||||
}
|
||||
|
||||
/* For larger than 1 unit, we do not accept */
|
||||
if (1e6 < unit) {
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid time unit %g!\nAcceptable units are [1e6|1e3|1|1e-3|1e-6|1e-9|1e-12|1e-15|1e-18]\n",
|
||||
unit);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
} /* namespace openfpga ends */
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef OPENFPGA_SCALE_H
|
||||
#define OPENFPGA_SCALE_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <string>
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
/* namespace openfpga begins */
|
||||
namespace openfpga {
|
||||
|
||||
bool same_float_number(const float& a,
|
||||
const float& b,
|
||||
const float& epsilon);
|
||||
|
||||
std::string unit_to_string(const float& unit);
|
||||
|
||||
std::string time_unit_to_string(const float& unit);
|
||||
|
||||
float string_to_unit(const std::string& scale);
|
||||
|
||||
float string_to_time_unit(const std::string& scale);
|
||||
|
||||
} /* namespace openfpga ends */
|
||||
|
||||
#endif
|
|
@ -9,6 +9,7 @@
|
|||
#include "command_exit_codes.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_scale.h"
|
||||
#include "openfpga_digest.h"
|
||||
|
||||
#include "circuit_library_utils.h"
|
||||
|
@ -31,6 +32,7 @@ int write_pnr_sdc(OpenfpgaContext& openfpga_ctx,
|
|||
CommandOptionId opt_output_dir = cmd.option("file");
|
||||
CommandOptionId opt_flatten_names = cmd.option("flatten_names");
|
||||
CommandOptionId opt_hierarchical = cmd.option("hierarchical");
|
||||
CommandOptionId opt_time_unit = cmd.option("time_unit");
|
||||
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");
|
||||
|
@ -53,6 +55,11 @@ int write_pnr_sdc(OpenfpgaContext& openfpga_ctx,
|
|||
|
||||
options.set_flatten_names(cmd_context.option_enable(cmd, opt_flatten_names));
|
||||
options.set_hierarchical(cmd_context.option_enable(cmd, opt_hierarchical));
|
||||
|
||||
if (true == cmd_context.option_enable(cmd, opt_time_unit)) {
|
||||
options.set_time_unit(string_to_time_unit(cmd_context.option_value(cmd, opt_time_unit)));
|
||||
}
|
||||
|
||||
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));
|
||||
|
@ -100,6 +107,7 @@ int write_analysis_sdc(OpenfpgaContext& openfpga_ctx,
|
|||
|
||||
CommandOptionId opt_output_dir = cmd.option("file");
|
||||
CommandOptionId opt_flatten_names = cmd.option("flatten_names");
|
||||
CommandOptionId opt_time_unit = cmd.option("time_unit");
|
||||
|
||||
/* This is an intermediate data structure which is designed to modularize the FPGA-SDC
|
||||
* Keep it independent from any other outside data structures
|
||||
|
@ -113,6 +121,10 @@ int write_analysis_sdc(OpenfpgaContext& openfpga_ctx,
|
|||
options.set_generate_sdc_analysis(true);
|
||||
options.set_flatten_names(cmd_context.option_enable(cmd, opt_flatten_names));
|
||||
|
||||
if (true == cmd_context.option_enable(cmd, opt_time_unit)) {
|
||||
options.set_time_unit(string_to_time_unit(cmd_context.option_value(cmd, opt_time_unit)));
|
||||
}
|
||||
|
||||
/* Collect global ports from the circuit library:
|
||||
* TODO: should we place this in the OpenFPGA context?
|
||||
*/
|
||||
|
|
|
@ -32,6 +32,10 @@ ShellCommandId add_openfpga_write_pnr_sdc_command(openfpga::Shell<OpenfpgaContex
|
|||
/* Add an option '--hierarchical' */
|
||||
shell_cmd.add_option("hierarchical", false, "Output SDC files hierachically (without full path in hierarchy)");
|
||||
|
||||
/* 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|kM]s");
|
||||
shell_cmd.set_option_require_value(time_unit_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--constrain_global_port' */
|
||||
shell_cmd.add_option("constrain_global_port", false, "Constrain all the global ports of FPGA fabric");
|
||||
|
||||
|
@ -95,6 +99,10 @@ ShellCommandId add_openfpga_write_analysis_sdc_command(openfpga::Shell<OpenfpgaC
|
|||
/* Add an option '--flatten_name' */
|
||||
shell_cmd.add_option("flatten_names", false, "Use flatten names (no wildcards) in SDC files");
|
||||
|
||||
/* 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|kM]s");
|
||||
shell_cmd.set_option_require_value(time_unit_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* 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");
|
||||
shell.set_command_class(shell_cmd_id, cmd_class_id);
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace openfpga {
|
|||
AnalysisSdcOption::AnalysisSdcOption(const std::string& sdc_dir) {
|
||||
sdc_dir_ = sdc_dir;
|
||||
flatten_names_ = false;
|
||||
time_unit_ = 1.;
|
||||
generate_sdc_analysis_ = false;
|
||||
}
|
||||
|
||||
|
@ -26,6 +27,10 @@ bool AnalysisSdcOption::flatten_names() const {
|
|||
return flatten_names_;
|
||||
}
|
||||
|
||||
float AnalysisSdcOption::time_unit() const {
|
||||
return time_unit_;
|
||||
}
|
||||
|
||||
bool AnalysisSdcOption::generate_sdc_analysis() const {
|
||||
return generate_sdc_analysis_;
|
||||
}
|
||||
|
@ -41,6 +46,10 @@ void AnalysisSdcOption::set_flatten_names(const bool& flatten_names) {
|
|||
flatten_names_ = flatten_names;
|
||||
}
|
||||
|
||||
void AnalysisSdcOption::set_time_unit(const float& time_unit) {
|
||||
time_unit_ = time_unit;
|
||||
}
|
||||
|
||||
void AnalysisSdcOption::set_generate_sdc_analysis(const bool& generate_sdc_analysis) {
|
||||
generate_sdc_analysis_ = generate_sdc_analysis;
|
||||
}
|
||||
|
|
|
@ -17,15 +17,18 @@ class AnalysisSdcOption {
|
|||
public: /* Public accessors */
|
||||
std::string sdc_dir() const;
|
||||
bool flatten_names() const;
|
||||
float time_unit() 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_time_unit(const float& time_unit);
|
||||
void set_generate_sdc_analysis(const bool& generate_sdc_analysis);
|
||||
private: /* Internal data */
|
||||
std::string sdc_dir_;
|
||||
bool generate_sdc_analysis_;
|
||||
bool flatten_names_;
|
||||
float time_unit_;
|
||||
};
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace openfpga {
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_analysis_sdc_io_delays(std::fstream& fp,
|
||||
const float& time_unit,
|
||||
const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
|
@ -74,8 +75,8 @@ void print_analysis_sdc_io_delays(std::fstream& fp,
|
|||
/* Reach here, it means a clock port and we need print constraints */
|
||||
fp << "create_clock ";
|
||||
fp << generate_sdc_port(operating_clock_port);
|
||||
fp << " -period " << std::setprecision(10) << critical_path_delay;
|
||||
fp << " -waveform {0 " << std::setprecision(10) << critical_path_delay / 2 << "}";
|
||||
fp << " -period " << std::setprecision(10) << critical_path_delay / time_unit;
|
||||
fp << " -waveform {0 " << std::setprecision(10) << critical_path_delay / (2 * time_unit) << "}";
|
||||
fp << std::endl;
|
||||
|
||||
/* Add an empty line as a splitter */
|
||||
|
@ -130,11 +131,11 @@ void print_analysis_sdc_io_delays(std::fstream& fp,
|
|||
*/
|
||||
if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) {
|
||||
print_sdc_set_port_input_delay(fp, module_mapped_io_port,
|
||||
operating_clock_ports[0], critical_path_delay);
|
||||
operating_clock_ports[0], critical_path_delay / time_unit);
|
||||
} else {
|
||||
VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk));
|
||||
print_sdc_set_port_output_delay(fp, module_mapped_io_port,
|
||||
operating_clock_ports[0], critical_path_delay);
|
||||
operating_clock_ports[0], critical_path_delay / time_unit);
|
||||
}
|
||||
|
||||
/* Mark this I/O has been used/wired */
|
||||
|
@ -251,7 +252,7 @@ void print_analysis_sdc(const AnalysisSdcOption& option,
|
|||
VTR_ASSERT(true == openfpga_ctx.module_graph().valid_module_id(top_module));
|
||||
|
||||
/* Create clock and set I/O ports with input/output delays */
|
||||
print_analysis_sdc_io_delays(fp,
|
||||
print_analysis_sdc_io_delays(fp, option.time_unit(),
|
||||
vpr_ctx.atom(), vpr_ctx.placement(),
|
||||
openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.io_location_map(),
|
||||
openfpga_ctx.module_graph(), top_module,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "vtr_time.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_scale.h"
|
||||
#include "openfpga_port.h"
|
||||
#include "openfpga_digest.h"
|
||||
#include "openfpga_side_manager.h"
|
||||
|
@ -43,6 +44,7 @@ namespace openfpga {
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_constrain_pb_pin_interc_timing(std::fstream& fp,
|
||||
const float& time_unit,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
t_pb_graph_pin* des_pb_graph_pin,
|
||||
|
@ -151,7 +153,7 @@ void print_pnr_sdc_constrain_pb_pin_interc_timing(std::fstream& fp,
|
|||
generate_sdc_port(src_port),
|
||||
des_instance_name,
|
||||
generate_sdc_port(des_port),
|
||||
des_pb_graph_pin->input_edges[iedge]->delay_max);
|
||||
des_pb_graph_pin->input_edges[iedge]->delay_max / time_unit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,6 +163,7 @@ void print_pnr_sdc_constrain_pb_pin_interc_timing(std::fstream& fp,
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_constrain_pb_interc_timing(std::fstream& fp,
|
||||
const float& time_unit,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
t_pb_graph_node* des_pb_graph_node,
|
||||
|
@ -176,7 +179,8 @@ void print_pnr_sdc_constrain_pb_interc_timing(std::fstream& fp,
|
|||
for (int ipin = 0; ipin < des_pb_graph_node->num_input_pins[iport]; ++ipin) {
|
||||
/* If this is a idle block, we set 0 to the selected edge*/
|
||||
/* Get the selected edge of current pin*/
|
||||
print_pnr_sdc_constrain_pb_pin_interc_timing(fp,
|
||||
print_pnr_sdc_constrain_pb_pin_interc_timing(fp,
|
||||
time_unit,
|
||||
module_manager, parent_module,
|
||||
&(des_pb_graph_node->input_pins[iport][ipin]),
|
||||
physical_mode,
|
||||
|
@ -189,6 +193,7 @@ void print_pnr_sdc_constrain_pb_interc_timing(std::fstream& fp,
|
|||
for (int iport = 0; iport < des_pb_graph_node->num_output_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < des_pb_graph_node->num_output_pins[iport]; ++ipin) {
|
||||
print_pnr_sdc_constrain_pb_pin_interc_timing(fp,
|
||||
time_unit,
|
||||
module_manager, parent_module,
|
||||
&(des_pb_graph_node->output_pins[iport][ipin]),
|
||||
physical_mode,
|
||||
|
@ -217,6 +222,7 @@ void print_pnr_sdc_constrain_pb_interc_timing(std::fstream& fp,
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_constrain_pb_graph_node_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const ModuleManager& module_manager,
|
||||
t_pb_graph_node* parent_pb_graph_node,
|
||||
t_mode* physical_mode,
|
||||
|
@ -242,6 +248,9 @@ void print_pnr_sdc_constrain_pb_graph_node_timing(const std::string& sdc_dir,
|
|||
/* Generate the descriptions*/
|
||||
print_sdc_file_header(fp, std::string("Timing constraints for Grid " + pb_module_name + " in PnR"));
|
||||
|
||||
/* Print time unit for the SDC file */
|
||||
print_sdc_timescale(fp, time_unit_to_string(time_unit));
|
||||
|
||||
/* We check output_pins of cur_pb_graph_node and its the input_edges
|
||||
* Built the interconnections between outputs of cur_pb_graph_node and outputs of child_pb_graph_node
|
||||
* child_pb_graph_node.output_pins -----------------> cur_pb_graph_node.outpins
|
||||
|
@ -250,6 +259,7 @@ void print_pnr_sdc_constrain_pb_graph_node_timing(const std::string& sdc_dir,
|
|||
* input_pins, edges, output_pins
|
||||
*/
|
||||
print_pnr_sdc_constrain_pb_interc_timing(fp,
|
||||
time_unit,
|
||||
module_manager, pb_module,
|
||||
parent_pb_graph_node,
|
||||
CIRCUIT_PB_PORT_OUTPUT,
|
||||
|
@ -268,6 +278,7 @@ void print_pnr_sdc_constrain_pb_graph_node_timing(const std::string& sdc_dir,
|
|||
t_pb_graph_node* child_pb_graph_node = &(parent_pb_graph_node->child_pb_graph_nodes[physical_mode->index][ipb][jpb]);
|
||||
/* For each child_pb_graph_node input pins*/
|
||||
print_pnr_sdc_constrain_pb_interc_timing(fp,
|
||||
time_unit,
|
||||
module_manager, pb_module,
|
||||
child_pb_graph_node,
|
||||
CIRCUIT_PB_PORT_INPUT,
|
||||
|
@ -291,6 +302,7 @@ void print_pnr_sdc_constrain_pb_graph_node_timing(const std::string& sdc_dir,
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_constrain_primitive_pb_graph_node(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const ModuleManager& module_manager,
|
||||
t_pb_graph_node* primitive_pb_graph_node,
|
||||
const bool& constrain_zero_delay_paths) {
|
||||
|
@ -350,6 +362,9 @@ void print_pnr_sdc_constrain_primitive_pb_graph_node(const std::string& sdc_dir,
|
|||
/* Generate the descriptions*/
|
||||
print_sdc_file_header(fp, std::string("Timing constraints for Grid " + pb_module_name + " in PnR"));
|
||||
|
||||
/* Print time unit for the SDC file */
|
||||
print_sdc_timescale(fp, time_unit_to_string(time_unit));
|
||||
|
||||
/* We traverse the pb_graph pins where we can find pin-to-pin timing annotation
|
||||
* We walk through output pins here, build timing constraints by pair each output to input
|
||||
* Clock pins are not walked through because they will be handled by clock tree synthesis
|
||||
|
@ -387,7 +402,7 @@ void print_pnr_sdc_constrain_primitive_pb_graph_node(const std::string& sdc_dir,
|
|||
generate_sdc_port(src_port),
|
||||
pb_module_name,
|
||||
generate_sdc_port(sink_port),
|
||||
tmax);
|
||||
tmax / time_unit);
|
||||
}
|
||||
|
||||
/* Find min delay between src and sink pin */
|
||||
|
@ -400,7 +415,7 @@ void print_pnr_sdc_constrain_primitive_pb_graph_node(const std::string& sdc_dir,
|
|||
generate_sdc_port(src_port),
|
||||
pb_module_name,
|
||||
generate_sdc_port(sink_port),
|
||||
tmin);
|
||||
tmin / time_unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -417,6 +432,7 @@ void print_pnr_sdc_constrain_primitive_pb_graph_node(const std::string& sdc_dir,
|
|||
*******************************************************************/
|
||||
static
|
||||
void rec_print_pnr_sdc_constrain_pb_graph_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const ModuleManager& module_manager,
|
||||
const VprDeviceAnnotation& device_annotation,
|
||||
t_pb_graph_node* parent_pb_graph_node,
|
||||
|
@ -433,7 +449,9 @@ void rec_print_pnr_sdc_constrain_pb_graph_timing(const std::string& sdc_dir,
|
|||
|
||||
/* Constrain the primitive node if a timing matrix is defined */
|
||||
if (true == is_primitive_pb_type(parent_pb_type)) {
|
||||
print_pnr_sdc_constrain_primitive_pb_graph_node(sdc_dir, module_manager,
|
||||
print_pnr_sdc_constrain_primitive_pb_graph_node(sdc_dir,
|
||||
time_unit,
|
||||
module_manager,
|
||||
parent_pb_graph_node,
|
||||
constrain_zero_delay_paths);
|
||||
return;
|
||||
|
@ -446,6 +464,7 @@ void rec_print_pnr_sdc_constrain_pb_graph_timing(const std::string& sdc_dir,
|
|||
|
||||
/* Write a SDC file for this pb_type */
|
||||
print_pnr_sdc_constrain_pb_graph_node_timing(sdc_dir,
|
||||
time_unit,
|
||||
module_manager,
|
||||
parent_pb_graph_node,
|
||||
physical_mode,
|
||||
|
@ -455,7 +474,9 @@ void rec_print_pnr_sdc_constrain_pb_graph_timing(const std::string& sdc_dir,
|
|||
* Note that we assume a full hierarchical P&R, we will only visit pb_graph_node of unique pb_type
|
||||
*/
|
||||
for (int ipb = 0; ipb < physical_mode->num_pb_type_children; ++ipb) {
|
||||
rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, module_manager,
|
||||
rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir,
|
||||
time_unit,
|
||||
module_manager,
|
||||
device_annotation,
|
||||
&(parent_pb_graph_node->child_pb_graph_nodes[physical_mode->index][ipb][0]),
|
||||
constrain_zero_delay_paths);
|
||||
|
@ -466,6 +487,7 @@ void rec_print_pnr_sdc_constrain_pb_graph_timing(const std::string& sdc_dir,
|
|||
* Top-level function to print timing constraints for pb_types
|
||||
*******************************************************************/
|
||||
void print_pnr_sdc_constrain_grid_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const DeviceContext& device_ctx,
|
||||
const VprDeviceAnnotation& device_annotation,
|
||||
const ModuleManager& module_manager,
|
||||
|
@ -485,7 +507,8 @@ void print_pnr_sdc_constrain_grid_timing(const std::string& sdc_dir,
|
|||
continue;
|
||||
}
|
||||
/* Special for I/O block, generate one module for each border side */
|
||||
rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, module_manager,
|
||||
rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, time_unit,
|
||||
module_manager,
|
||||
device_annotation,
|
||||
pb_graph_head,
|
||||
constrain_zero_delay_paths);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
namespace openfpga {
|
||||
|
||||
void print_pnr_sdc_constrain_grid_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const DeviceContext& device_ctx,
|
||||
const VprDeviceAnnotation& device_annotation,
|
||||
const ModuleManager& module_manager,
|
||||
|
|
|
@ -13,6 +13,7 @@ PnrSdcOption::PnrSdcOption(const std::string& sdc_dir) {
|
|||
sdc_dir_ = sdc_dir;
|
||||
hierarchical_ = false;
|
||||
flatten_names_ = false;
|
||||
time_unit_ = 1.;
|
||||
constrain_global_port_ = false;
|
||||
constrain_non_clock_global_port_ = false;
|
||||
constrain_grid_ = false;
|
||||
|
@ -39,6 +40,10 @@ bool PnrSdcOption::hierarchical() const {
|
|||
return hierarchical_;
|
||||
}
|
||||
|
||||
float PnrSdcOption::time_unit() const {
|
||||
return time_unit_;
|
||||
}
|
||||
|
||||
bool PnrSdcOption::generate_sdc_pnr() const {
|
||||
return constrain_global_port_
|
||||
|| constrain_grid_
|
||||
|
@ -100,6 +105,10 @@ void PnrSdcOption::set_hierarchical(const bool& hierarchical) {
|
|||
hierarchical_ = hierarchical;
|
||||
}
|
||||
|
||||
void PnrSdcOption::set_time_unit(const float& time_unit) {
|
||||
time_unit_ = time_unit;
|
||||
}
|
||||
|
||||
void PnrSdcOption::set_generate_sdc_pnr(const bool& generate_sdc_pnr) {
|
||||
constrain_global_port_ = generate_sdc_pnr;
|
||||
constrain_grid_ = generate_sdc_pnr;
|
||||
|
|
|
@ -18,6 +18,7 @@ class PnrSdcOption {
|
|||
std::string sdc_dir() const;
|
||||
bool flatten_names() const;
|
||||
bool hierarchical() const;
|
||||
float time_unit() const;
|
||||
bool generate_sdc_pnr() const;
|
||||
bool constrain_global_port() const;
|
||||
bool constrain_non_clock_global_port() const;
|
||||
|
@ -32,6 +33,7 @@ class PnrSdcOption {
|
|||
void set_sdc_dir(const std::string& sdc_dir);
|
||||
void set_flatten_names(const bool& flatten_names);
|
||||
void set_hierarchical(const bool& hierarchical);
|
||||
void set_time_unit(const float& time_unit);
|
||||
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);
|
||||
|
@ -46,6 +48,7 @@ class PnrSdcOption {
|
|||
std::string sdc_dir_;
|
||||
bool flatten_names_;
|
||||
bool hierarchical_;
|
||||
float time_unit_;
|
||||
bool constrain_global_port_;
|
||||
bool constrain_non_clock_global_port_;
|
||||
bool constrain_grid_;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "vtr_time.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_scale.h"
|
||||
#include "openfpga_port.h"
|
||||
#include "openfpga_side_manager.h"
|
||||
#include "openfpga_digest.h"
|
||||
|
@ -49,6 +50,7 @@ float find_pnr_sdc_switch_tmax(const t_rr_switch_inf& switch_inf) {
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const std::string& module_path,
|
||||
const ModuleManager& module_manager,
|
||||
|
@ -104,7 +106,7 @@ void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp,
|
|||
generate_sdc_port(module_manager.module_port(sb_module, module_input_port)),
|
||||
module_path,
|
||||
generate_sdc_port(module_manager.module_port(sb_module, module_output_port)),
|
||||
switch_delays[module_input_port]);
|
||||
switch_delays[module_input_port] / time_unit);
|
||||
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(true == hierarchical);
|
||||
|
@ -112,7 +114,7 @@ void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp,
|
|||
module_manager,
|
||||
sb_module, module_input_port,
|
||||
sb_module, module_output_port,
|
||||
switch_delays[module_input_port]);
|
||||
switch_delays[module_input_port] / time_unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +129,7 @@ void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp,
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const std::string& module_path,
|
||||
const ModuleManager& module_manager,
|
||||
|
@ -152,6 +155,9 @@ void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir,
|
|||
/* Generate the descriptions*/
|
||||
print_sdc_file_header(fp, std::string("Constrain timing of Switch Block " + sb_module_name + " for PnR"));
|
||||
|
||||
/* Print time unit for the SDC file */
|
||||
print_sdc_timescale(fp, time_unit_to_string(time_unit));
|
||||
|
||||
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
|
||||
SideManager side_manager(side);
|
||||
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
|
||||
|
@ -166,6 +172,7 @@ void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir,
|
|||
}
|
||||
/* This is a MUX, constrain all the paths from an input to an output */
|
||||
print_pnr_sdc_constrain_sb_mux_timing(fp,
|
||||
time_unit,
|
||||
hierarchical,
|
||||
module_path,
|
||||
module_manager, sb_module,
|
||||
|
@ -186,6 +193,7 @@ void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir,
|
|||
* This function is designed for flatten routing hierarchy
|
||||
*******************************************************************/
|
||||
void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
|
@ -223,6 +231,7 @@ void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_di
|
|||
module_path += std::string(")") + std::string("\\");
|
||||
|
||||
print_pnr_sdc_constrain_sb_timing(sdc_dir,
|
||||
time_unit,
|
||||
hierarchical,
|
||||
module_path,
|
||||
module_manager,
|
||||
|
@ -238,6 +247,7 @@ void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_di
|
|||
* This function is designed for compact routing hierarchy
|
||||
*******************************************************************/
|
||||
void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
|
@ -283,6 +293,7 @@ void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_di
|
|||
module_path += std::string(")") + std::string("\\");
|
||||
|
||||
print_pnr_sdc_constrain_sb_timing(sdc_dir,
|
||||
time_unit,
|
||||
hierarchical,
|
||||
module_path,
|
||||
module_manager,
|
||||
|
@ -298,6 +309,7 @@ void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_di
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const std::string& module_path,
|
||||
const ModuleManager& module_manager,
|
||||
|
@ -373,7 +385,7 @@ void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp,
|
|||
module_manager,
|
||||
cb_module, module_input_port,
|
||||
cb_module, module_output_port,
|
||||
switch_delays[module_input_port]);
|
||||
switch_delays[module_input_port] / time_unit);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(false == hierarchical);
|
||||
print_pnr_sdc_regexp_constrain_max_delay(fp,
|
||||
|
@ -381,7 +393,7 @@ void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp,
|
|||
generate_sdc_port(module_manager.module_port(cb_module, module_input_port)),
|
||||
std::string(module_path),
|
||||
generate_sdc_port(module_manager.module_port(cb_module, module_output_port)),
|
||||
switch_delays[module_input_port]);
|
||||
switch_delays[module_input_port] / time_unit);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -393,6 +405,7 @@ void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp,
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const std::string& module_path,
|
||||
const ModuleManager& module_manager,
|
||||
|
@ -420,6 +433,9 @@ void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir,
|
|||
/* Generate the descriptions*/
|
||||
print_sdc_file_header(fp, std::string("Constrain timing of Connection Block " + cb_module_name + " for PnR"));
|
||||
|
||||
/* Print time unit for the SDC file */
|
||||
print_sdc_timescale(fp, time_unit_to_string(time_unit));
|
||||
|
||||
/* Contrain each routing track inside the connection block */
|
||||
for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) {
|
||||
/* Create a port description for the input */
|
||||
|
@ -463,7 +479,7 @@ void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir,
|
|||
module_manager,
|
||||
cb_module, input_port_id,
|
||||
cb_module, output_port_id,
|
||||
routing_segment_delay);
|
||||
routing_segment_delay / time_unit);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(false == hierarchical);
|
||||
print_pnr_sdc_regexp_constrain_max_delay(fp,
|
||||
|
@ -471,7 +487,7 @@ void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir,
|
|||
generate_sdc_port(module_manager.module_port(cb_module, input_port_id)),
|
||||
std::string(module_path),
|
||||
generate_sdc_port(module_manager.module_port(cb_module, output_port_id)),
|
||||
routing_segment_delay);
|
||||
routing_segment_delay / time_unit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -484,6 +500,7 @@ void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir,
|
|||
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) {
|
||||
const RRNodeId& ipin_rr_node = rr_gsb.get_ipin_node(cb_ipin_side, inode);
|
||||
print_pnr_sdc_constrain_cb_mux_timing(fp,
|
||||
time_unit,
|
||||
hierarchical, module_path,
|
||||
module_manager, cb_module,
|
||||
rr_graph, rr_gsb, cb_type,
|
||||
|
@ -502,6 +519,7 @@ void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir,
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
|
@ -542,6 +560,7 @@ void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
module_path += std::string(")") + std::string("\\");
|
||||
|
||||
print_pnr_sdc_constrain_cb_timing(sdc_dir,
|
||||
time_unit,
|
||||
hierarchical,
|
||||
module_path,
|
||||
module_manager,
|
||||
|
@ -559,6 +578,7 @@ void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
* and print SDC file for each of them
|
||||
*******************************************************************/
|
||||
void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
|
@ -569,14 +589,16 @@ void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
/* Start time count */
|
||||
vtr::ScopedStartFinishTimer timer("Write SDC for constrain Connection Block timing for P&R flow");
|
||||
|
||||
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, hierarchical,
|
||||
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, time_unit,
|
||||
hierarchical,
|
||||
module_manager, top_module,
|
||||
rr_graph,
|
||||
device_rr_gsb,
|
||||
CHANX,
|
||||
constrain_zero_delay_paths);
|
||||
|
||||
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, hierarchical,
|
||||
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, time_unit,
|
||||
hierarchical,
|
||||
module_manager, top_module,
|
||||
rr_graph,
|
||||
device_rr_gsb,
|
||||
|
@ -589,6 +611,7 @@ void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
* This function is designed for compact routing hierarchy
|
||||
*******************************************************************/
|
||||
void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
|
@ -631,6 +654,7 @@ void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
module_path += std::string(")") + std::string("\\");
|
||||
|
||||
print_pnr_sdc_constrain_cb_timing(sdc_dir,
|
||||
time_unit,
|
||||
hierarchical,
|
||||
module_path,
|
||||
module_manager,
|
||||
|
@ -670,6 +694,7 @@ void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
module_path += std::string(")") + std::string("\\");
|
||||
|
||||
print_pnr_sdc_constrain_cb_timing(sdc_dir,
|
||||
time_unit,
|
||||
hierarchical,
|
||||
module_path,
|
||||
module_manager,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
namespace openfpga {
|
||||
|
||||
void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
|
@ -26,6 +27,7 @@ void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_di
|
|||
const bool& constrain_zero_delay_paths);
|
||||
|
||||
void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
|
@ -34,6 +36,7 @@ void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_di
|
|||
const bool& constrain_zero_delay_paths);
|
||||
|
||||
void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
|
@ -42,6 +45,7 @@ void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_di
|
|||
const bool& constrain_zero_delay_paths);
|
||||
|
||||
void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_dir,
|
||||
const float& time_unit,
|
||||
const bool& hierarchical,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
|
|
|
@ -442,6 +442,7 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
|||
if (true == sdc_options.constrain_sb()) {
|
||||
if (true == compact_routing_hierarchy) {
|
||||
print_pnr_sdc_compact_routing_constrain_sb_timing(sdc_options.sdc_dir(),
|
||||
sdc_options.time_unit(),
|
||||
sdc_options.hierarchical(),
|
||||
module_manager,
|
||||
top_module,
|
||||
|
@ -451,6 +452,7 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
|||
} else {
|
||||
VTR_ASSERT_SAFE (false == compact_routing_hierarchy);
|
||||
print_pnr_sdc_flatten_routing_constrain_sb_timing(sdc_options.sdc_dir(),
|
||||
sdc_options.time_unit(),
|
||||
sdc_options.hierarchical(),
|
||||
module_manager,
|
||||
top_module,
|
||||
|
@ -464,6 +466,7 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
|||
if (true == sdc_options.constrain_cb()) {
|
||||
if (true == compact_routing_hierarchy) {
|
||||
print_pnr_sdc_compact_routing_constrain_cb_timing(sdc_options.sdc_dir(),
|
||||
sdc_options.time_unit(),
|
||||
sdc_options.hierarchical(),
|
||||
module_manager,
|
||||
top_module,
|
||||
|
@ -473,6 +476,7 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
|||
} else {
|
||||
VTR_ASSERT_SAFE (false == compact_routing_hierarchy);
|
||||
print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_options.sdc_dir(),
|
||||
sdc_options.time_unit(),
|
||||
sdc_options.hierarchical(),
|
||||
module_manager,
|
||||
top_module,
|
||||
|
@ -485,6 +489,7 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
|||
/* Output Timing constraints for Programmable blocks */
|
||||
if (true == sdc_options.constrain_grid()) {
|
||||
print_pnr_sdc_constrain_grid_timing(sdc_options.sdc_dir(),
|
||||
sdc_options.time_unit(),
|
||||
device_ctx,
|
||||
device_annotation,
|
||||
module_manager,
|
||||
|
|
|
@ -38,6 +38,21 @@ void print_sdc_file_header(std::fstream& fp,
|
|||
fp << std::endl;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write a timescale definition in SDC file
|
||||
*******************************************************************/
|
||||
void print_sdc_timescale(std::fstream& fp,
|
||||
const std::string& timescale) {
|
||||
|
||||
valid_file_stream(fp);
|
||||
|
||||
fp << "#############################################" << std::endl;
|
||||
fp << "#\tDefine time unit " << std::endl;
|
||||
fp << "#############################################" << std::endl;
|
||||
fp << "set_units -time " << timescale << std::endl;
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write a port in SDC format
|
||||
*******************************************************************/
|
||||
|
|
|
@ -19,6 +19,9 @@ namespace openfpga {
|
|||
void print_sdc_file_header(std::fstream& fp,
|
||||
const std::string& usage);
|
||||
|
||||
void print_sdc_timescale(std::fstream& fp,
|
||||
const std::string& timescale);
|
||||
|
||||
std::string generate_sdc_port(const BasicPort& port);
|
||||
|
||||
void print_pnr_sdc_constrain_max_delay(std::fstream& fp,
|
||||
|
|
Loading…
Reference in New Issue