From c2e5d6b8e273f819259510102fad4e72a6d1b1e5 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 25 Mar 2020 14:38:13 -0600 Subject: [PATCH] add options to dsiable SDC for non-clock global ports --- openfpga/src/base/openfpga_sdc.cpp | 2 + openfpga/src/base/openfpga_sdc_command.cpp | 3 + openfpga/src/fpga_sdc/pnr_sdc_global_port.cpp | 192 ++++++++++++++++++ openfpga/src/fpga_sdc/pnr_sdc_global_port.h | 27 +++ openfpga/src/fpga_sdc/pnr_sdc_option.cpp | 9 + openfpga/src/fpga_sdc/pnr_sdc_option.h | 3 + openfpga/src/fpga_sdc/pnr_sdc_writer.cpp | 103 +--------- 7 files changed, 239 insertions(+), 100 deletions(-) create mode 100644 openfpga/src/fpga_sdc/pnr_sdc_global_port.cpp create mode 100644 openfpga/src/fpga_sdc/pnr_sdc_global_port.h diff --git a/openfpga/src/base/openfpga_sdc.cpp b/openfpga/src/base/openfpga_sdc.cpp index 8b708f133..a83d0b797 100644 --- a/openfpga/src/base/openfpga_sdc.cpp +++ b/openfpga/src/base/openfpga_sdc.cpp @@ -27,6 +27,7 @@ void write_pnr_sdc(OpenfpgaContext& openfpga_ctx, CommandOptionId opt_output_dir = cmd.option("file"); 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"); CommandOptionId opt_constrain_sb = cmd.option("constrain_sb"); CommandOptionId opt_constrain_cb = cmd.option("constrain_cb"); @@ -45,6 +46,7 @@ void write_pnr_sdc(OpenfpgaContext& openfpga_ctx, PnrSdcOption options(sdc_dir_path); 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)); options.set_constrain_sb(cmd_context.option_enable(cmd, opt_constrain_sb)); options.set_constrain_cb(cmd_context.option_enable(cmd, opt_constrain_cb)); diff --git a/openfpga/src/base/openfpga_sdc_command.cpp b/openfpga/src/base/openfpga_sdc_command.cpp index 91d65aa0a..7d194ba5b 100644 --- a/openfpga/src/base/openfpga_sdc_command.cpp +++ b/openfpga/src/base/openfpga_sdc_command.cpp @@ -29,6 +29,9 @@ ShellCommandId add_openfpga_write_pnr_sdc_command(openfpga::Shell +#include +#include + +/* Headers from vtrutil library */ +#include "vtr_assert.h" +#include "vtr_time.h" +#include "vtr_log.h" + +/* Headers from openfpgautil library */ +#include "openfpga_port.h" +#include "openfpga_digest.h" + +#include "sdc_writer_naming.h" +#include "sdc_writer_utils.h" +#include "pnr_sdc_global_port.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/******************************************************************** + * Print SDC constraint for a clock port + * This format is derived from the open-source SDC syntax, + * which is supposed to be generic + * + * This function is design to the SDC writer for any port + * wants to be treated as a clock port + *******************************************************************/ +static +void print_pnr_sdc_clock_port(std::fstream& fp, + const BasicPort& port_to_constrain, + const float& clock_period) { + valid_file_stream(fp); + + fp << "create_clock"; + fp << " -name " << generate_sdc_port(port_to_constrain); + fp << " -period " << std::setprecision(10) << clock_period; + fp << " -waveform {0 " << std::setprecision(10) << clock_period / 2 << "}"; + fp << " [get_ports{" << generate_sdc_port(port_to_constrain) << "}]"; + fp << std::endl; +} + +/******************************************************************** + * Print SDC constraints for the clock ports which are the global ports + * of FPGA fabric + * + * For programming clock, we give a fixed period, while for operating + * clock, we constrain with critical path delay + *******************************************************************/ +static +void print_pnr_sdc_global_clock_ports(std::fstream& fp, + const float& programming_critical_path_delay, + const float& operating_critical_path_delay, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports) { + + valid_file_stream(fp); + + /* Get clock port from the global port */ + for (const CircuitPortId& clock_port : global_ports) { + if (CIRCUIT_MODEL_PORT_CLOCK != circuit_lib.port_type(clock_port)) { + continue; + } + /* Reach here, it means a clock port and we need print constraints */ + float clock_period = operating_critical_path_delay; + + /* For programming clock, we give a fixed period */ + if (true == circuit_lib.port_is_prog(clock_port)) { + clock_period = programming_critical_path_delay; + /* Print comments */ + fp << "##################################################" << std::endl; + fp << "# Create programmable clock " << std::endl; + fp << "##################################################" << std::endl; + } else { + /* Print comments */ + fp << "##################################################" << std::endl; + fp << "# Create clock " << std::endl; + fp << "##################################################" << std::endl; + } + + for (const size_t& pin : circuit_lib.pins(clock_port)) { + BasicPort port_to_constrain(circuit_lib.port_prefix(clock_port), pin, pin); + + print_pnr_sdc_clock_port(fp, + port_to_constrain, + clock_period); + } + } +} + +/******************************************************************** + * Print SDC constraints for the non-clock ports which are the global ports + * of FPGA fabric + * Here, we will the treat the non-clock ports as the clock ports + * in the CTS + * Note that, this may be applied to the reset, set and other global + * signals which do need very balanced delays to each sink + *******************************************************************/ +static +void print_pnr_sdc_global_non_clock_ports(std::fstream& fp, + const float& operating_critical_path_delay, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports) { + + valid_file_stream(fp); + + /* For non-clock port from the global port: give a fixed period */ + for (const CircuitPortId& global_port : global_ports) { + if (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(global_port)) { + continue; + } + + /* Print comments */ + fp << "##################################################" << std::endl; + fp << "# Constrain other global ports " << std::endl; + fp << "##################################################" << std::endl; + + /* Reach here, it means a non-clock global port and we need print constraints */ + float clock_period = operating_critical_path_delay; + for (const size_t& pin : circuit_lib.pins(global_port)) { + BasicPort port_to_constrain(circuit_lib.port_prefix(global_port), pin, pin); + + print_pnr_sdc_clock_port(fp, + port_to_constrain, + clock_period); + } + } +} + +/******************************************************************** + * Print a SDC file to constrain the global ports of FPGA fabric + * in particular clock ports + * + * This ports to appear in this file will be treated in Clock Tree + * Synthesis (CTS) + * + * For non-clock global ports, we have an option to select if they + * should be treated in CTS or not + * In general, we do not recommend to do this + *******************************************************************/ +void print_pnr_sdc_global_ports(const std::string& sdc_dir, + const float& programming_critical_path_delay, + const float& operating_critical_path_delay, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports, + const bool& constrain_non_clock_port) { + + /* Create the file name for Verilog netlist */ + std::string sdc_fname(sdc_dir + std::string(SDC_GLOBAL_PORTS_FILE_NAME)); + + /* Start time count */ + std::string timer_message = std::string("Write SDC for constraining clocks 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("Clock contraints for PnR")); + + print_pnr_sdc_global_clock_ports(fp, + programming_critical_path_delay, + operating_critical_path_delay, + circuit_lib, + global_ports); + + if (true == constrain_non_clock_port) { + print_pnr_sdc_global_non_clock_ports(fp, + operating_critical_path_delay, + circuit_lib, + global_ports); + + } + + /* Close file handler */ + fp.close(); +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/fpga_sdc/pnr_sdc_global_port.h b/openfpga/src/fpga_sdc/pnr_sdc_global_port.h new file mode 100644 index 000000000..444482106 --- /dev/null +++ b/openfpga/src/fpga_sdc/pnr_sdc_global_port.h @@ -0,0 +1,27 @@ +#ifndef PNR_SDC_GLBOAL_PORT_H +#define PNR_SDC_GLBOAL_PORT_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include +#include "circuit_library.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +void print_pnr_sdc_global_ports(const std::string& sdc_dir, + const float& programming_critical_path_delay, + const float& operating_critical_path_delay, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports, + const bool& constrain_non_clock_port); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/fpga_sdc/pnr_sdc_option.cpp b/openfpga/src/fpga_sdc/pnr_sdc_option.cpp index 3a3906b50..a5143776e 100644 --- a/openfpga/src/fpga_sdc/pnr_sdc_option.cpp +++ b/openfpga/src/fpga_sdc/pnr_sdc_option.cpp @@ -12,6 +12,7 @@ namespace openfpga { PnrSdcOption::PnrSdcOption(const std::string& sdc_dir) { sdc_dir_ = sdc_dir; constrain_global_port_ = false; + constrain_non_clock_global_port_ = false; constrain_grid_ = false; constrain_sb_ = false; constrain_cb_ = false; @@ -41,6 +42,10 @@ bool PnrSdcOption::constrain_global_port() const { return constrain_global_port_; } +bool PnrSdcOption::constrain_non_clock_global_port() const { + return constrain_non_clock_global_port_; +} + bool PnrSdcOption::constrain_grid() const { return constrain_grid_; } @@ -86,6 +91,10 @@ void PnrSdcOption::set_constrain_global_port(const bool& constrain_global_port) constrain_global_port_ = constrain_global_port; } +void PnrSdcOption::set_constrain_non_clock_global_port(const bool& constrain_non_clock_global_port) { + constrain_non_clock_global_port_ = constrain_non_clock_global_port; +} + void PnrSdcOption::set_constrain_grid(const bool& constrain_grid) { constrain_grid_ = constrain_grid; } diff --git a/openfpga/src/fpga_sdc/pnr_sdc_option.h b/openfpga/src/fpga_sdc/pnr_sdc_option.h index a485a1946..b81bfaefe 100644 --- a/openfpga/src/fpga_sdc/pnr_sdc_option.h +++ b/openfpga/src/fpga_sdc/pnr_sdc_option.h @@ -18,6 +18,7 @@ class PnrSdcOption { std::string sdc_dir() const; bool generate_sdc_pnr() const; bool constrain_global_port() const; + bool constrain_non_clock_global_port() const; bool constrain_grid() const; bool constrain_sb() const; bool constrain_cb() const; @@ -28,6 +29,7 @@ class PnrSdcOption { void set_sdc_dir(const std::string& sdc_dir); 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); void set_constrain_grid(const bool& constrain_grid); void set_constrain_sb(const bool& constrain_sb); void set_constrain_cb(const bool& constrain_cb); @@ -37,6 +39,7 @@ class PnrSdcOption { private: /* Internal data */ std::string sdc_dir_; bool constrain_global_port_; + bool constrain_non_clock_global_port_; bool constrain_grid_; bool constrain_sb_; bool constrain_cb_; diff --git a/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp b/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp index 9d1478037..b005ca6ce 100644 --- a/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp +++ b/openfpga/src/fpga_sdc/pnr_sdc_writer.cpp @@ -28,6 +28,7 @@ #include "sdc_writer_naming.h" #include "sdc_writer_utils.h" #include "sdc_memory_utils.h" +#include "pnr_sdc_global_port.h" #include "pnr_sdc_routing_writer.h" #include "pnr_sdc_grid_writer.h" #include "pnr_sdc_writer.h" @@ -35,105 +36,6 @@ /* begin namespace openfpga */ namespace openfpga { -/******************************************************************** - * Print a SDC file to constrain the global ports of FPGA fabric - * in particular clock ports - * - * For programming clock, we give a fixed period, while for operating - * clock, we constrain with critical path delay - *******************************************************************/ -static -void print_pnr_sdc_global_ports(const std::string& sdc_dir, - const float& programming_critical_path_delay, - const float& operating_critical_path_delay, - const CircuitLibrary& circuit_lib, - const std::vector& global_ports) { - - /* Create the file name for Verilog netlist */ - std::string sdc_fname(sdc_dir + std::string(SDC_GLOBAL_PORTS_FILE_NAME)); - - /* Start time count */ - std::string timer_message = std::string("Write SDC for constraining clocks 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("Clock contraints for PnR")); - - /* Get clock port from the global port */ - for (const CircuitPortId& clock_port : global_ports) { - if (CIRCUIT_MODEL_PORT_CLOCK != circuit_lib.port_type(clock_port)) { - continue; - } - /* Reach here, it means a clock port and we need print constraints */ - float clock_period = operating_critical_path_delay; - - /* For programming clock, we give a fixed period */ - if (true == circuit_lib.port_is_prog(clock_port)) { - clock_period = programming_critical_path_delay; - /* Print comments */ - fp << "##################################################" << std::endl; - fp << "# Create programmable clock " << std::endl; - fp << "##################################################" << std::endl; - } else { - /* Print comments */ - fp << "##################################################" << std::endl; - fp << "# Create clock " << std::endl; - fp << "##################################################" << std::endl; - } - - for (const size_t& pin : circuit_lib.pins(clock_port)) { - BasicPort port_to_constrain(circuit_lib.port_prefix(clock_port), pin, pin); - - fp << "create_clock "; - fp << generate_sdc_port(port_to_constrain) << "-period "; - fp << std::setprecision(10) << clock_period; - fp << " -waveform {0 "; - fp << std::setprecision(10) << clock_period / 2; - fp << "}" << std::endl; - - fp << std::endl; - } - } - - /* For non-clock port from the global port: give a fixed period */ - for (const CircuitPortId& global_port : global_ports) { - if (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(global_port)) { - continue; - } - - /* Print comments */ - fp << "##################################################" << std::endl; - fp << "# Constrain other global ports " << std::endl; - fp << "##################################################" << std::endl; - - /* Reach here, it means a non-clock global port and we need print constraints */ - float clock_period = operating_critical_path_delay; - for (const size_t& pin : circuit_lib.pins(global_port)) { - BasicPort port_to_constrain(circuit_lib.port_prefix(global_port), pin, pin); - fp << "create_clock "; - fp << generate_sdc_port(port_to_constrain) << "-period "; - fp << std::setprecision(10) << clock_period; - fp << " -waveform {0 "; - fp << std::setprecision(10) << clock_period / 2; - fp << "} "; - fp << "[list [get_ports { " << generate_sdc_port(port_to_constrain) << "}]]" << std::endl; - - fp << "set_drive 0 " << generate_sdc_port(port_to_constrain) << std::endl; - - fp << std::endl; - } - } - - /* Close file handler */ - fp.close(); -} - /******************************************************************** * Break combinational loops in FPGA fabric, which mainly come from * configurable memory cells. @@ -354,7 +256,8 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options, print_pnr_sdc_global_ports(sdc_options.sdc_dir(), programming_critical_path_delay, operating_critical_path_delay, - circuit_lib, global_ports); + circuit_lib, global_ports, + sdc_options.constrain_non_clock_global_port()); } std::string top_module_name = generate_fpga_top_module_name();