start refactoring sdc generator, make it geneirc by placing it in parallel to Verilog generator
This commit is contained in:
parent
d391983e8c
commit
14e7744fee
|
@ -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<CircuitPortId> 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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<size_t> 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<size_t> 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<size_t> my_itobin_vec(const size_t& in_int, const size_t& bin_len) {
|
||||
std::vector<size_t> 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));
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/********************************************************************
|
||||
* Most utilized functions in FPGA X2P framework
|
||||
*******************************************************************/
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#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: <dir_path>/<file_name>
|
||||
* This function will return <file_name>
|
||||
********************************************************************/
|
||||
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: <dir_path>/<file_name>
|
||||
* This function will return <dir_path>
|
||||
********************************************************************/
|
||||
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<size_t> 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<size_t> 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<size_t> my_itobin_vec(const size_t& in_int, const size_t& bin_len) {
|
||||
std::vector<size_t> 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;
|
||||
}
|
||||
|
|
@ -3,16 +3,28 @@
|
|||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#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<size_t> 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<size_t> 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<size_t> 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<size_t> 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,
|
||||
|
|
|
@ -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 <ctime>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#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<CircuitPortId>& 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<CircuitPortId>& 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef PNR_SDC_WRITER_H
|
||||
#define PNR_SDC_WRITER_H
|
||||
|
||||
#include <string>
|
||||
#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<CircuitPortId>& global_ports);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,34 @@
|
|||
/********************************************************************
|
||||
* Useful APIs for SDC generator
|
||||
*******************************************************************/
|
||||
#include <ctime>
|
||||
#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<CircuitPortId>& 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);
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef SDC_API_H
|
||||
#define SDC_API_H
|
||||
|
||||
#include <vector>
|
||||
#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<CircuitPortId>& global_ports);
|
||||
|
||||
#endif
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 <string>
|
||||
|
||||
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
|
|
@ -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
|
|
@ -0,0 +1,52 @@
|
|||
/********************************************************************
|
||||
* This file include most utilized functions to be used in SDC writers
|
||||
*******************************************************************/
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
|
||||
#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 <port_name>[<lsb>:<msb>]
|
||||
* others require a format of <port_type> [<lsb>:<msb>] <port_name>
|
||||
*/
|
||||
/* When LSB == MSB, we can use a simplified format <port_type>[<lsb>]*/
|
||||
if ( 1 == port.get_width()) {
|
||||
size_str = "[" + std::to_string(port.get_lsb()) + "]";
|
||||
}
|
||||
sdc_line = port.get_name() + size_str;
|
||||
|
||||
return sdc_line;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef SDC_WRITER_UTILS_H
|
||||
#define SDC_WRITER_UTILS_H
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#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
|
|
@ -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;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
Loading…
Reference in New Issue