diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c index 4665bc0bb..966a8cb5d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c @@ -24,9 +24,11 @@ /* Include spice support headers*/ #include "linkedlist.h" +#include "circuit_library_utils.h" #include "fpga_x2p_utils.h" #include "fpga_x2p_backannotate_utils.h" #include "fpga_x2p_setup.h" +#include "fpga_x2p_naming.h" #include "mux_library_builder.h" #include "build_device_module.h" @@ -36,6 +38,7 @@ #include "spice_api.h" #include "verilog_api.h" +#include "sdc_api.h" #include "fpga_bitstream.h" #include "fpga_x2p_reserved_words.h" @@ -139,6 +142,28 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, vpr_setup, Arch, vpr_setup.FileNameOpts.CircuitName); } + + /* Run SDC Generator */ + std::string src_dir = find_path_dir_name(std::string(vpr_setup.FileNameOpts.CircuitName)); + + /* Use current directory if there is not dir path given */ + if (true == src_dir.empty()) { + src_dir = std::string("./"); + } else { + src_dir = format_dir_path(src_dir); + } + SdcOption sdc_options(format_dir_path(src_dir + std::string(FPGA_X2P_DEFAULT_SDC_DIR))); + sdc_options.set_generate_sdc_pnr(TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_sdc_pnr); + sdc_options.set_generate_sdc_analysis(TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_sdc_analysis); + + if (true == sdc_options.generate_sdc()) { + std::vector global_ports = find_circuit_library_global_ports(Arch.spice->circuit_lib); + /* TODO: the critical path delay unit should be explicit! */ + fpga_sdc_generator(sdc_options, + Arch.spice->spice_params.stimulate_params.vpr_crit_path_delay / 1e-9, + Arch.spice->circuit_lib, global_ports); + } + /* Xifan Tang: Bitstream Generator */ if ((TRUE == vpr_setup.FPGA_SPICE_Opts.BitstreamGenOpts.gen_bitstream) &&(FALSE == vpr_setup.FPGA_SPICE_Opts.SpiceOpts.do_spice) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h index ece002039..56f3c627d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h @@ -13,6 +13,8 @@ #include "circuit_library.h" #include "vpr_types.h" +constexpr char* FPGA_X2P_DEFAULT_SDC_DIR = "SDC"; + std::string generate_mux_node_name(const size_t& node_level, const bool& add_buffer_postfix); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c index 9f73bc651..e61a4defb 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c @@ -85,26 +85,6 @@ char* format_dir_path(char* dir_path) { return ret; } -/************************************************ - * Format a path of directory: - * 1. Replace "\" with "/" - * 2. add a "/" if the string does not end with a "/" - ***********************************************/ -std::string format_dir_path(const std::string& dir_path) { - std::string ret = dir_path; - - /* Replace "\" with "/" */ - std::replace(ret.begin(), ret.end(), '\\', '/'); - - /* Complete the string with a "/" if it does not end with that */ - if ('/' != ret.back()) { - ret.push_back('/'); - } - - return ret; -} - - int try_access_file(char* file_path) { /* F_OK checks existence and also R_OK, W_OK, X_OK, * for readable, writable, excutable @@ -251,18 +231,6 @@ char* chomp_file_name_postfix(char* file_name) { return ret; } -void check_file_handler(std::fstream& fp) { - /* Make sure we have a valid file handler*/ - /* Print out debugging information for if the file is not opened/created properly */ - if (!fp.is_open() || !fp.good()) { - vpr_printf(TIO_MESSAGE_ERROR, - "(FILE:%s,LINE[%d])Failure in create file!\n", - __FILE__, __LINE__); - exit(1); - } -} - - /* Print SRAM bits, typically in a comment line */ void fprint_commented_sram_bits(FILE* fp, int num_sram_bits, int* sram_bits) { @@ -633,21 +601,6 @@ char* my_ito1hot(int in_int, int bin_len) { return ret; } -/* Convert an integer to an one-hot encoding integer array */ -std::vector my_ito1hot_vec(const size_t& in_int, const size_t& bin_len) { - /* Make sure we do not have any overflow! */ - VTR_ASSERT ( (in_int <= bin_len) ); - - /* Initialize */ - std::vector ret(bin_len, 0); - - if (bin_len == in_int) { - return ret; /* all zero case */ - } - ret[in_int] = 1; /* Keep a good sequence of bits */ - - return ret; -} /* Converter an integer to a binary string */ int* my_itobin_int(int in_int, int bin_len) { @@ -669,24 +622,6 @@ int* my_itobin_int(int in_int, int bin_len) { return ret; } -/* Converter an integer to a binary vector */ -std::vector my_itobin_vec(const size_t& in_int, const size_t& bin_len) { - std::vector ret(bin_len, 0); - - /* Make sure we do not have any overflow! */ - VTR_ASSERT ( (in_int < pow(2., bin_len)) ); - - size_t temp = in_int; - for (size_t i = 0; i < bin_len; i++) { - if (1 == temp % 2) { - ret[i] = 1; /* Keep a good sequence of bits */ - } - temp = temp / 2; - } - - return ret; -} - /* Converter an integer to a binary string */ char* my_itobin(int in_int, int bin_len) { char* ret = (char*) my_calloc (bin_len + 1, sizeof(char)); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.cpp new file mode 100644 index 000000000..1f49526f0 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.cpp @@ -0,0 +1,135 @@ +/******************************************************************** + * Most utilized functions in FPGA X2P framework + *******************************************************************/ +#include +#include + +#include "vtr_assert.h" +#include "fpga_x2p_utils.h" + +/******************************************************************** + * Format a directory path: + * 1. Replace "\" with "/" + * 2. add a "/" if the string does not end with a "/" + *******************************************************************/ +std::string format_dir_path(const std::string& dir_path_to_format) { + std::string formatted_dir_path = dir_path_to_format; + + char illegal_back_slash = '\\'; + char legal_back_slash = '/'; + +#ifdef _WIN32 +/* For windows OS, replace any '/' with '\' */ + char illegal_back_slash = '/'; + char legal_back_slash = '\\'; +#endif + + /* Replace "\" with "/" */ + std::replace(formatted_dir_path.begin(), formatted_dir_path.end(), illegal_back_slash, legal_back_slash); + + /* Add a back slash the string is not ended like this! */ + if (legal_back_slash != formatted_dir_path.back()) { + formatted_dir_path.push_back(legal_back_slash); + } + + return formatted_dir_path; +} + +/******************************************************************** + * Extract full file name from a full path of file + * For example: / + * This function will return + ********************************************************************/ +std::string find_path_file_name(const std::string& file_name) { + + char back_slash = '/'; + +#ifdef _WIN32 +/* For windows OS, replace any '/' with '\' */ + char back_slash = '\\'; +#endif + + /* Find the last '/' in the string and return the left part */ + size_t found = file_name.rfind(back_slash); + if (found != std::string::npos) { + return file_name.substr(found + 1); + } + /* Not found, return an empty string */ + return std::string(); +} + +/******************************************************************** + * Extract full directory path from a full path of file + * For example: / + * This function will return + ********************************************************************/ +std::string find_path_dir_name(const std::string& file_name) { + + char back_slash = '/'; + +#ifdef _WIN32 +/* For windows OS, replace any '/' with '\' */ + char back_slash = '\\'; +#endif + + /* Find the last '/' in the string and return the left part */ + size_t found = file_name.rfind(back_slash); + if (found != std::string::npos) { + return file_name.substr(0, found); + } + /* Not found, return an empty string */ + return std::string(); +} + +/******************************************************************** + * Check if the file stream is valid + ********************************************************************/ +void check_file_handler(std::fstream& fp) { + /* Make sure we have a valid file handler*/ + /* Print out debugging information for if the file is not opened/created properly */ + if (!fp.is_open() || !fp.good()) { + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d])Failure in create file!\n", + __FILE__, __LINE__); + exit(1); + } +} + +/******************************************************************** + * Convert an integer to an one-hot encoding integer array + ********************************************************************/ +std::vector my_ito1hot_vec(const size_t& in_int, const size_t& bin_len) { + /* Make sure we do not have any overflow! */ + VTR_ASSERT ( (in_int <= bin_len) ); + + /* Initialize */ + std::vector ret(bin_len, 0); + + if (bin_len == in_int) { + return ret; /* all zero case */ + } + ret[in_int] = 1; /* Keep a good sequence of bits */ + + return ret; +} + +/******************************************************************** + * Converter an integer to a binary vector + ********************************************************************/ +std::vector my_itobin_vec(const size_t& in_int, const size_t& bin_len) { + std::vector ret(bin_len, 0); + + /* Make sure we do not have any overflow! */ + VTR_ASSERT ( (in_int < pow(2., bin_len)) ); + + size_t temp = in_int; + for (size_t i = 0; i < bin_len; i++) { + if (1 == temp % 2) { + ret[i] = 1; /* Keep a good sequence of bits */ + } + temp = temp / 2; + } + + return ret; +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h index 114d2d604..4ad93fc2b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h @@ -3,16 +3,28 @@ #include #include +#include #include "my_free_fwd.h" #include "rr_blocks_naming.h" +std::string format_dir_path(const std::string& dir_path_to_format); + void check_file_handler(std::fstream& fp); +std::vector my_ito1hot_vec(const size_t& in_int, const size_t& bin_len); + +std::string find_path_dir_name(const std::string& file_name); + +std::string find_path_file_name(const std::string& file_name); + +std::vector my_itobin_vec(const size_t& in_int, const size_t& bin_len); + +/* Old functions */ + char* my_gettime(); char* format_dir_path(char* dir_path); /* TODO: TO BE REMOVED !!! */ -std::string format_dir_path(const std::string& dir_path); int try_access_file(char* file_path); @@ -66,14 +78,10 @@ t_spice_transistor_type* find_mosfet_tech_lib(t_spice_tech_lib tech_lib, char* my_ito1hot(int in_int, int bin_len); -std::vector my_ito1hot_vec(const size_t& in_int, const size_t& bin_len); - char* my_itobin(int in_int, int bin_len); int* my_itobin_int(int in_int, int bin_len); -std::vector my_itobin_vec(const size_t& in_int, const size_t& bin_len); - char* my_itoa(int input); char* fpga_spice_create_one_subckt_filename(const char* file_name_prefix, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.cpp new file mode 100644 index 000000000..d2f41e023 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.cpp @@ -0,0 +1,158 @@ +/******************************************************************** + * 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 physical design for each module + * in FPGA fabric, such as Configurable Logic Blocks (CLBs), + * Heterogeneous blocks, Switch Blocks (SBs) and Connection Blocks (CBs) + * + * 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 +#include +#include + +#include "vtr_assert.h" +#include "device_port.h" + +#include "util.h" + +#include "fpga_x2p_utils.h" + +#include "sdc_writer_naming.h" +#include "sdc_writer_utils.h" +#include "pnr_sdc_writer.h" + +/******************************************************************** + * Local variables + *******************************************************************/ +constexpr float SDC_FIXED_PROG_CLOCK_PERIOD = 100; +constexpr float SDC_FIXED_CLOCK_PERIOD = 10; + +/******************************************************************** + * 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& 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_CLOCK_FILE_NAME)); + + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for constraining clocks for P&R flow: %s ...", + sdc_fname.c_str()); + + /* Start time count */ + clock_t t_start = clock(); + + /* Create the file stream */ + std::fstream fp; + fp.open(sdc_fname, std::fstream::out | std::fstream::trunc); + + check_file_handler(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 (SPICE_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 = critical_path_delay; + + /* For programming clock, we give a fixed period */ + if (true == circuit_lib.port_is_prog(clock_port)) { + clock_period = SDC_FIXED_PROG_CLOCK_PERIOD; + /* 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 (SPICE_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 = SDC_FIXED_CLOCK_PERIOD; + 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(); + + /* End time count */ + clock_t t_end = clock(); + + float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC; + vpr_printf(TIO_MESSAGE_INFO, + "took %g seconds\n", + run_time_sec); +} + +/******************************************************************** + * Top-level function to print a number of SDC files in different purpose + * This function will generate files upon the options provided by users + * 1. Design constraints for CLBs + * 2. Design constraints for Switch Blocks + * 3. Design constraints for Connection Blocks + * 4. Design constraints for breaking the combinational loops in FPGA fabric + *******************************************************************/ +void print_pnr_sdc(const SdcOption& sdc_options, + const float& critical_path_delay, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports) { + + /* Part 1. Constrain global ports */ + if (true == sdc_options.constrain_global_port()) { + print_pnr_sdc_global_ports(sdc_options.sdc_dir(), critical_path_delay, circuit_lib, global_ports); + } +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.h new file mode 100644 index 000000000..8b0b4496a --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.h @@ -0,0 +1,15 @@ +#ifndef PNR_SDC_WRITER_H +#define PNR_SDC_WRITER_H + +#include +#include "vtr_geometry.h" +#include "vpr_types.h" +#include "rr_blocks.h" +#include "sdc_option.h" + +void print_pnr_sdc(const SdcOption& sdc_options, + const float& critical_path_delay, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.cpp new file mode 100644 index 000000000..8162f9ff1 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.cpp @@ -0,0 +1,34 @@ +/******************************************************************** + * Useful APIs for SDC generator + *******************************************************************/ +#include +#include "pnr_sdc_writer.h" + +#include "sdc_api.h" + +/******************************************************************** + * Top-level function to launch SDC generator + *******************************************************************/ +void fpga_sdc_generator(const SdcOption& sdc_options, + const float& critical_path_delay, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports) { + vpr_printf(TIO_MESSAGE_INFO, + "SDC generator starts..."); + + /* Start time count */ + clock_t t_start = clock(); + + if (true == sdc_options.generate_sdc_pnr()) { + print_pnr_sdc(sdc_options.sdc_dir(), critical_path_delay, circuit_lib, global_ports); + } + + /* End time count */ + clock_t t_end = clock(); + + float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC; + vpr_printf(TIO_MESSAGE_INFO, + "SDC generation took %g seconds\n", + run_time_sec); + +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.h b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.h new file mode 100644 index 000000000..fe630963e --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.h @@ -0,0 +1,13 @@ +#ifndef SDC_API_H +#define SDC_API_H + +#include +#include "sdc_option.h" +#include "circuit_library.h" + +void fpga_sdc_generator(const SdcOption& sdc_options, + const float& critical_path_delay, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.cpp new file mode 100644 index 000000000..ca9753b5d --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.cpp @@ -0,0 +1,92 @@ +/******************************************************************** + * Member functions for a data structure which includes all the options for the SDC generator + ********************************************************************/ +#include "sdc_option.h" + +/******************************************************************** + * Public Constructors + ********************************************************************/ +SdcOption::SdcOption(const std::string& sdc_dir) { + sdc_dir_ = sdc_dir; + constrain_global_port_ = true; + constrain_grid_ = true; + constrain_sb_ = true; + constrain_cb_ = true; + break_loop_ = true; +} + + +/******************************************************************** + * Public accessors + ********************************************************************/ +std::string SdcOption::sdc_dir() const { + return sdc_dir_; +} + +bool SdcOption::generate_sdc() const { + return generate_sdc_pnr_ && generate_sdc_analysis_; +} + +bool SdcOption::generate_sdc_pnr() const { + return generate_sdc_pnr_; +} + +bool SdcOption::generate_sdc_analysis() const { + return generate_sdc_analysis_; +} + +bool SdcOption::constrain_global_port() const { + return constrain_global_port_; +} + +bool SdcOption::constrain_grid() const { + return constrain_grid_; +} + +bool SdcOption::constrain_sb() const { + return constrain_sb_; +} + +bool SdcOption::constrain_cb() const { + return constrain_cb_; +} + +bool SdcOption::break_loop() const { + return break_loop_; +} + +/******************************************************************** + * Public mutators + ********************************************************************/ +void SdcOption::set_sdc_dir(const std::string& sdc_dir) { + sdc_dir_ = sdc_dir; +} + +void SdcOption::set_generate_sdc_pnr(const bool& generate_sdc_pnr) { + generate_sdc_pnr_ = generate_sdc_pnr; +} + +void SdcOption::set_generate_sdc_analysis(const bool& generate_sdc_analysis) { + generate_sdc_analysis_ = generate_sdc_analysis; +} + +void SdcOption::set_constrain_global_port(const bool& constrain_global_port) { + constrain_global_port_ = constrain_global_port; +} + +void SdcOption::set_constrain_grid(const bool& constrain_grid) { + constrain_grid_ = constrain_grid; +} + +void SdcOption::set_constrain_sb(const bool& constrain_sb) { + constrain_sb_ = constrain_sb; +} + +void SdcOption::set_constrain_cb(const bool& constrain_cb) { + constrain_cb_ = constrain_cb; +} + +void SdcOption::set_break_loop(const bool& break_loop) { + break_loop_ = break_loop; +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.h b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.h new file mode 100644 index 000000000..244ffc796 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.h @@ -0,0 +1,43 @@ +#ifndef SDC_OPTION_H +#define SDC_OPTION_H + +/******************************************************************** + * A data structure to include all the options for the SDC generator + ********************************************************************/ + +#include + +class SdcOption { + public: /* Public Constructors */ + SdcOption(const std::string& sdc_dir); + public: /* Public accessors */ + std::string sdc_dir() const; + bool generate_sdc() const; + bool generate_sdc_pnr() const; + bool generate_sdc_analysis() const; + bool constrain_global_port() const; + bool constrain_grid() const; + bool constrain_sb() const; + bool constrain_cb() const; + bool break_loop() const; + public: /* Public mutators */ + void set_sdc_dir(const std::string& sdc_dir); + void set_generate_sdc_pnr(const bool& generate_sdc_pnr); + void set_generate_sdc_analysis(const bool& generate_sdc_analysis); + void set_constrain_global_port(const bool& constrain_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); + void set_break_loop(const bool& break_loop); + private: /* Internal data */ + std::string sdc_dir_; + bool generate_sdc_pnr_; + bool constrain_global_port_; + bool constrain_grid_; + bool constrain_sb_; + bool constrain_cb_; + bool break_loop_; + bool generate_sdc_analysis_; +}; + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_naming.h new file mode 100644 index 000000000..0fdb2f2b7 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_naming.h @@ -0,0 +1,10 @@ +#ifndef SDC_WRITER_NAMING_H +#define SDC_WRITER_NAMING_H + +constexpr char* SDC_CLOCK_FILE_NAME = "clb_clock.sdc"; +constexpr char* SDC_BENCHMARK_ANALYSIS_FILE_NAME= "fpga_top_analysis.sdc"; +constexpr char* SDC_BREAK_COMB_LOOP_FILE_NAME = "break_loop.sdc"; +constexpr char* SDC_CB_FILE_NAME = "cb.sdc"; +constexpr char* SDC_SB_FILE_NAME = "sb.sdc"; + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.cpp new file mode 100644 index 000000000..12ef60b6b --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.cpp @@ -0,0 +1,52 @@ +/******************************************************************** + * This file include most utilized functions to be used in SDC writers + *******************************************************************/ +#include +#include + +#include "fpga_x2p_utils.h" + +#include "sdc_writer_utils.h" + +/******************************************************************** + * Write a head (description) in SDC file + *******************************************************************/ +void print_sdc_file_header(std::fstream& fp, + const std::string& usage) { + + check_file_handler(fp); + + auto end = std::chrono::system_clock::now(); + std::time_t end_time = std::chrono::system_clock::to_time_t(end); + + fp << "#############################################" << std::endl; + fp << "#\tSynopsys Design Constraints (SDC)" << std::endl; + fp << "#\tFor FPGA fabric " << std::endl; + fp << "#\tDescription: " << usage << std::endl; + fp << "#\tAuthor: Xifan TANG " << std::endl; + fp << "#\tOrganization: University of Utah " << std::endl; + fp << "#\tDate: " << std::ctime(&end_time); + fp << "#############################################" << std::endl; + fp << std::endl; +} + + +/******************************************************************** + * Write a port in SDC format + *******************************************************************/ +std::string generate_sdc_port(const BasicPort& port) { + std::string sdc_line; + + std::string size_str = "[" + std::to_string(port.get_lsb()) + ":" + std::to_string(port.get_msb()) + "]"; + + /* Only connection require a format of [:] + * others require a format of [:] + */ + /* When LSB == MSB, we can use a simplified format []*/ + if ( 1 == port.get_width()) { + size_str = "[" + std::to_string(port.get_lsb()) + "]"; + } + sdc_line = port.get_name() + size_str; + + return sdc_line; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.h new file mode 100644 index 000000000..b3d916f57 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.h @@ -0,0 +1,13 @@ +#ifndef SDC_WRITER_UTILS_H +#define SDC_WRITER_UTILS_H + +#include +#include +#include "device_port.h" + +void print_sdc_file_header(std::fstream& fp, + const std::string& usage); + +std::string generate_sdc_port(const BasicPort& port); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp index 51ddd8107..41766444b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp @@ -42,7 +42,7 @@ void print_verilog_file_header(std::fstream& fp, fp << "//-------------------------------------------" << std::endl; fp << "//----- Time scale -----" << std::endl; fp << "`timescale 1ns / 1ps" << std::endl; - fp << "\n"; + fp << std::endl; } /********************************************************************