From f70f387f9f7c6448bcb9285985ab04760a3e1d19 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Nov 2019 20:51:49 -0600 Subject: [PATCH 01/68] minor tuning on ini compilation --- libs/external/libini/CMakeLists.txt | 5 +++-- .../fpga_x2p/verilog/simulation_info_writer.cpp | 14 +++++++------- .../SRC/fpga_x2p/verilog/simulation_info_writer.h | 14 +++++++------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/libs/external/libini/CMakeLists.txt b/libs/external/libini/CMakeLists.txt index 2730c6325..c09ff863b 100644 --- a/libs/external/libini/CMakeLists.txt +++ b/libs/external/libini/CMakeLists.txt @@ -7,6 +7,7 @@ files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS) #Create the library add_library(libini STATIC - ${LIB_HEADERS}) + ${LIB_HEADERS}) + target_include_directories(libini PUBLIC ${LIB_INCLUDE_DIRS}) -set_target_properties(libini PROPERTIES PREFIX "" LINKER_LANGUAGE CXX) \ No newline at end of file +set_target_properties(libini PROPERTIES PREFIX "" LINKER_LANGUAGE CXX) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp index 67850403d..21b11c08e 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp @@ -22,13 +22,13 @@ * Top-level function to write an ini file which contains exchangeable * information, in order to interface different Verilog simulators ********************************************************************/ -void print_verilog_simulation_info(const int &num_operating_clock_cycles, - const std::string &verilog_dir_formatted, - const std::string &chomped_circuit_name, - const std::string &src_dir_path, - const size_t &num_program_clock_cycles, - const float &prog_clock_freq, - const float &op_clock_freq) { +void print_verilog_simulation_info(const int& num_operating_clock_cycles, + const std::string& verilog_dir_formatted, + const std::string& chomped_circuit_name, + const std::string& src_dir_path, + const size_t& num_program_clock_cycles, + const float& prog_clock_freq, + const float& op_clock_freq) { mINI::INIStructure ini; // std::map units_map; // units_map['s']=1; // units_map['ms']=1E-3; // units_map['us']=1E-6; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h index feedb8e94..ce0798fdf 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h @@ -3,11 +3,11 @@ #include -void print_verilog_simulation_info(const int &num_operating_clock_cycles, - const std::string &verilog_dir_formatted, - const std::string &chomped_circuit_name, - const std::string &src_dir_path, - const size_t &num_program_clock_cycles, - const float &prog_clock_freq, - const float &op_clock_freq); +void print_verilog_simulation_info(const int& num_operating_clock_cycles, + const std::string& verilog_dir_formatted, + const std::string& chomped_circuit_name, + const std::string& src_dir_path, + const size_t& num_program_clock_cycles, + const float& prog_clock_freq, + const float& op_clock_freq); #endif From e9ed64c92694be23405d31b8d0c8c7e8c8f8893b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Nov 2019 21:17:35 -0600 Subject: [PATCH 02/68] try to let cmake identify libini --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f9964539..a6d51a7c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -182,6 +182,13 @@ set_target_properties(libace ace LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ace2" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ace2") +# Set output locations to be in the main source tree under the relevant folder +set_target_properties(libini + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/external/libini" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/external/libini" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/external/libini") + # Set output locations to be in the main source tree under the relevant folder set_target_properties(libvtrutil PROPERTIES From 17f816effd216d571537f6805b60b91425f61ee3 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Nov 2019 21:26:22 -0600 Subject: [PATCH 03/68] try to uncache libini --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9d68dc6f4..88d4f25e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ cache: - $TRAVIS_BUILD_DIR/abc - $TRAVIS_BUILD_DIR/yosys - $TRAVIS_BUILD_DIR/ace2 - - $TRAVIS_BUILD_DIR/libs +# - $TRAVIS_BUILD_DIR/libs - $HOME/.ccache - $HOME/deps From 495000c6494be4bf18d1ec1baf76ebc854e92a62 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Nov 2019 21:37:17 -0600 Subject: [PATCH 04/68] recover caching for libs --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 88d4f25e2..9d68dc6f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ cache: - $TRAVIS_BUILD_DIR/abc - $TRAVIS_BUILD_DIR/yosys - $TRAVIS_BUILD_DIR/ace2 -# - $TRAVIS_BUILD_DIR/libs + - $TRAVIS_BUILD_DIR/libs - $HOME/.ccache - $HOME/deps From 5bae8fecde11bf489abfa52706451f2cc9c2ac05 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Nov 2019 23:26:08 -0600 Subject: [PATCH 05/68] add debugging mode to see why travis failed --- .travis/script.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis/script.sh b/.travis/script.sh index bbd72cec4..7c5aab29b 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -19,19 +19,19 @@ end_section "OpenFPGA.build" start_section "OpenFPGA.TaskTun" "${GREEN}..Running_Regression..${NC}" cd - echo -e "Testing single-mode architectures"; -python3 openfpga_flow/scripts/run_fpga_task.py single_mode +python3 openfpga_flow/scripts/run_fpga_task.py single_mode --debug --show_thread_logs #python3 openfpga_flow/scripts/run_fpga_task.py s298 echo -e "Testing multi-mode architectures"; -python3 openfpga_flow/scripts/run_fpga_task.py blif_vpr_flow --maxthreads 4 +python3 openfpga_flow/scripts/run_fpga_task.py blif_vpr_flow --maxthreads 4 --debug --show_thread_logs echo -e "Testing compact routing techniques"; -python3 openfpga_flow/scripts/run_fpga_task.py compact_routing +python3 openfpga_flow/scripts/run_fpga_task.py compact_routing --debug --show_thread_logs echo -e "Testing tileable architectures"; -python3 openfpga_flow/scripts/run_fpga_task.py tileable_routing +python3 openfpga_flow/scripts/run_fpga_task.py tileable_routing --debug --show_thread_logs echo -e "Testing Verilog generation with explicit port mapping "; -python3 openfpga_flow/scripts/run_fpga_task.py explicit_verilog +python3 openfpga_flow/scripts/run_fpga_task.py explicit_verilog --debug --show_thread_logs end_section "OpenFPGA.TaskTun" From 358e9892acab5f367c40024898c7017405afa9b7 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 00:09:13 -0600 Subject: [PATCH 06/68] reduce some error message to warnings --- vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp | 9 ++++++--- vpr7_x2p/vpr/SRC/route/rr_graph.c | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp b/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp index 4ceab180e..5efabf0bc 100644 --- a/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp +++ b/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp @@ -579,14 +579,17 @@ void check_circuit_library(const CircuitLibrary& circuit_lib) { num_err += check_required_default_circuit_model(circuit_lib, SPICE_MODEL_WIRE); /* If we have any errors, exit */ - vpr_printf(TIO_MESSAGE_INFO, - "Finished checking circuit library with %d errors!\n", - num_err); if (0 < num_err) { + vpr_printf(TIO_MESSAGE_INFO, + "Finished checking circuit library with %d errors!\n", + num_err); exit(1); } + vpr_printf(TIO_MESSAGE_INFO, + "Checking circuit library passed.\n"); + return; } diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.c b/vpr7_x2p/vpr/SRC/route/rr_graph.c index 1c9c01e18..c637473a4 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.c @@ -1920,7 +1920,7 @@ static void check_all_tracks_reach_pins(t_type_ptr type, for (itrack = 0; itrack < nodes_per_chan; itrack++) { if (num_conns_to_track[itrack] <= 0) { - vpr_printf(TIO_MESSAGE_ERROR, "check_all_tracks_reach_pins: Track %d does not connect to any CLB %ss.\n", + vpr_printf(TIO_MESSAGE_WARNING, "check_all_tracks_reach_pins: Track %d does not connect to any CLB %ss.\n", itrack, (ipin_or_opin == DRIVER ? "OPIN" : "IPIN")); } } From c3db8805999477a0f7dd764f344989d3a14a5ac1 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 09:21:02 -0600 Subject: [PATCH 07/68] adding explicit file path to simulation info writer --- .../fpga_x2p/verilog/simulation_info_writer.cpp | 17 +++++++++-------- .../fpga_x2p/verilog/simulation_info_writer.h | 1 + vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c | 3 +++ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp index 21b11c08e..93474da0b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp @@ -23,9 +23,10 @@ * information, in order to interface different Verilog simulators ********************************************************************/ void print_verilog_simulation_info(const int& num_operating_clock_cycles, - const std::string& verilog_dir_formatted, - const std::string& chomped_circuit_name, - const std::string& src_dir_path, + const std::string& parent_dir, + const std::string& verilog_dir, + const std::string& circuit_name, + const std::string& src_dir, const size_t& num_program_clock_cycles, const float& prog_clock_freq, const float& op_clock_freq) { @@ -42,14 +43,14 @@ void print_verilog_simulation_info(const int& num_operating_clock_cycles, 1. / op_clock_freq); ini["SIMULATION_DECK"]["PROJECTNAME "] = "ModelSimProject"; - ini["SIMULATION_DECK"]["BENCHMARK "] = chomped_circuit_name; - ini["SIMULATION_DECK"]["TOP_TB"] = chomped_circuit_name + std::string("_top_formal_verification_random_tb"); + ini["SIMULATION_DECK"]["BENCHMARK "] = circuit_name; + ini["SIMULATION_DECK"]["TOP_TB"] = circuit_name + std::string("_top_formal_verification_random_tb"); ini["SIMULATION_DECK"]["SIMTIME "] = std::to_string(simulation_time_period); ini["SIMULATION_DECK"]["UNIT "] = "ms"; - ini["SIMULATION_DECK"]["VERILOG_PATH "] = std::string(src_dir_path); + ini["SIMULATION_DECK"]["VERILOG_PATH "] = std::string(src_dir); ini["SIMULATION_DECK"]["VERILOG_FILE1"] = std::string(defines_verilog_file_name); - ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(chomped_circuit_name + "_include_netlists.v"); + ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(circuit_name + "_include_netlists.v"); - mINI::INIFile file("SimulationDeckInfo.ini"); + mINI::INIFile file(parent_dir + "SimulationDeckInfo.ini"); file.generate(ini, true); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h index ce0798fdf..6be4b8f47 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h @@ -4,6 +4,7 @@ #include void print_verilog_simulation_info(const int& num_operating_clock_cycles, + const std::string& parent_dir, const std::string& verilog_dir_formatted, const std::string& chomped_circuit_name, const std::string& src_dir_path, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 998a8f2db..74a680d6c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -431,7 +431,10 @@ void vpr_fpga_verilog(ModuleManager& module_manager, print_verilog_random_top_testbench(std::string(chomped_circuit_name), random_top_testbench_file_path, std::string(src_dir_path), L_logical_blocks, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, Arch.spice->spice_params); + + /* Print exchangeable files which contains simulation settings */ print_verilog_simulation_info(Arch.spice->spice_params.meas_params.sim_num_clock_cycle, + std::string(format_dir_path(chomped_parent_dir)), std::string(msim_dir_path), std::string(chomped_circuit_name), std::string(src_dir_path), From d5d7450ce7b0433a7ba4a4994b41caf945b56eb7 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 09:46:12 -0600 Subject: [PATCH 08/68] make simulation ini writing as an option --- vpr7_x2p/vpr/SRC/base/OptionTokens.c | 1 + vpr7_x2p/vpr/SRC/base/OptionTokens.h | 1 + vpr7_x2p/vpr/SRC/base/ReadOptions.c | 2 ++ vpr7_x2p/vpr/SRC/base/SetupVPR.c | 5 +++++ vpr7_x2p/vpr/SRC/base/vpr_api.c | 1 + vpr7_x2p/vpr/SRC/base/vpr_types.h | 1 + vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c | 2 ++ 7 files changed, 13 insertions(+) diff --git a/vpr7_x2p/vpr/SRC/base/OptionTokens.c b/vpr7_x2p/vpr/SRC/base/OptionTokens.c index 78b956ce3..cdf5eef91 100644 --- a/vpr7_x2p/vpr/SRC/base/OptionTokens.c +++ b/vpr7_x2p/vpr/SRC/base/OptionTokens.c @@ -100,6 +100,7 @@ struct s_TokenPair OptionBaseTokenList[] = { { "fpga_verilog_report_timing_rpt_path", OT_FPGA_VERILOG_SYN_REPORT_TIMING_RPT_PATH }, /* Specify the simulator path for Verilog netlists */ { "fpga_verilog_print_sdc_pnr", OT_FPGA_VERILOG_SYN_PRINT_SDC_PNR }, /* Specify the simulator path for Verilog netlists */ { "fpga_verilog_print_sdc_analysis", OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS }, /* Specify the simulator path for Verilog netlists */ + { "fpga_verilog_print_simulation_ini", OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI }, /* Specify the simulator path for Verilog netlists */ /* Xifan Tang: Bitstream generator */ { "fpga_bitstream_generator", OT_FPGA_BITSTREAM_GENERATOR }, /* turn on bitstream generator, and specify the output file */ // { "fpga_bitstream_output_file", OT_FPGA_BITSTREAM_OUTPUT_FILE }, /* turn on bitstream generator, and specify the output file */ // AA: temporarily deprecated diff --git a/vpr7_x2p/vpr/SRC/base/OptionTokens.h b/vpr7_x2p/vpr/SRC/base/OptionTokens.h index 46a44ac05..706a81b24 100644 --- a/vpr7_x2p/vpr/SRC/base/OptionTokens.h +++ b/vpr7_x2p/vpr/SRC/base/OptionTokens.h @@ -117,6 +117,7 @@ enum e_OptionBaseToken { OT_FPGA_VERILOG_SYN_REPORT_TIMING_RPT_PATH, OT_FPGA_VERILOG_SYN_PRINT_SDC_PNR, OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS, + OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI, /* Xifan Tang: Bitstream generator */ OT_FPGA_BITSTREAM_GENERATOR, OT_FPGA_BITSTREAM_OUTPUT_FILE, diff --git a/vpr7_x2p/vpr/SRC/base/ReadOptions.c b/vpr7_x2p/vpr/SRC/base/ReadOptions.c index 108e9d355..54c323f9c 100644 --- a/vpr7_x2p/vpr/SRC/base/ReadOptions.c +++ b/vpr7_x2p/vpr/SRC/base/ReadOptions.c @@ -559,6 +559,8 @@ ProcessOption(INP char **Args, INOUTP t_options * Options) { return Args; case OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS: return Args; + case OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI: + return Args; /* Xifan TANG: Bitstream generator */ case OT_FPGA_BITSTREAM_GENERATOR: return Args; diff --git a/vpr7_x2p/vpr/SRC/base/SetupVPR.c b/vpr7_x2p/vpr/SRC/base/SetupVPR.c index 5b0e90004..1cb3fba67 100644 --- a/vpr7_x2p/vpr/SRC/base/SetupVPR.c +++ b/vpr7_x2p/vpr/SRC/base/SetupVPR.c @@ -1113,6 +1113,7 @@ static void SetupSynVerilogOpts(t_options Options, syn_verilog_opts->print_sdc_pnr = FALSE; syn_verilog_opts->print_sdc_analysis = FALSE; syn_verilog_opts->include_icarus_simulator = FALSE; + syn_verilog_opts->print_simulation_ini = FALSE; /* Turn on Syn_verilog options */ if (Options.Count[OT_FPGA_VERILOG_SYN]) { @@ -1183,6 +1184,10 @@ static void SetupSynVerilogOpts(t_options Options, syn_verilog_opts->print_sdc_analysis = TRUE; } + if (Options.Count[OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI]) { + syn_verilog_opts->print_simulation_ini = TRUE; + } + /* SynVerilog needs the input from spice modeling */ if (FALSE == arch->read_xml_spice) { arch->read_xml_spice = syn_verilog_opts->dump_syn_verilog; diff --git a/vpr7_x2p/vpr/SRC/base/vpr_api.c b/vpr7_x2p/vpr/SRC/base/vpr_api.c index 7d1730883..5148daa23 100644 --- a/vpr7_x2p/vpr/SRC/base/vpr_api.c +++ b/vpr7_x2p/vpr/SRC/base/vpr_api.c @@ -211,6 +211,7 @@ void vpr_print_usage(void) { vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_report_timing_rpt_path \n"); vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_sdc_pnr\n"); vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_sdc_analysis\n"); + vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_simulation_ini\n"); /* Xifan Tang: Bitstream generator */ vpr_printf(TIO_MESSAGE_INFO, "Bitstream Generator Options:\n"); vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_bitstream_generator\n"); diff --git a/vpr7_x2p/vpr/SRC/base/vpr_types.h b/vpr7_x2p/vpr/SRC/base/vpr_types.h index 7b87d664a..95ae3784c 100755 --- a/vpr7_x2p/vpr/SRC/base/vpr_types.h +++ b/vpr7_x2p/vpr/SRC/base/vpr_types.h @@ -1281,6 +1281,7 @@ struct s_syn_verilog_opts { boolean print_report_timing_tcl; boolean print_sdc_pnr; boolean print_sdc_analysis; + boolean print_simulation_ini; }; /* Xifan TANG: bitstream generator */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 74a680d6c..192e3dc63 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -431,7 +431,9 @@ void vpr_fpga_verilog(ModuleManager& module_manager, print_verilog_random_top_testbench(std::string(chomped_circuit_name), random_top_testbench_file_path, std::string(src_dir_path), L_logical_blocks, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, Arch.spice->spice_params); + } + if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_simulation_ini) { /* Print exchangeable files which contains simulation settings */ print_verilog_simulation_info(Arch.spice->spice_params.meas_params.sim_num_clock_cycle, std::string(format_dir_path(chomped_parent_dir)), From e1a7a2895af3c8d4a5cb49de55b702625d5505da Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 09:59:34 -0600 Subject: [PATCH 09/68] simulation ini file name can be customizable --- vpr7_x2p/vpr/SRC/base/ReadOptions.c | 2 +- vpr7_x2p/vpr/SRC/base/ReadOptions.h | 1 + vpr7_x2p/vpr/SRC/base/SetupVPR.c | 1 + vpr7_x2p/vpr/SRC/base/vpr_api.c | 2 +- vpr7_x2p/vpr/SRC/base/vpr_types.h | 1 + .../SRC/fpga_x2p/verilog/simulation_info_writer.cpp | 13 +++++++++++-- .../SRC/fpga_x2p/verilog/simulation_info_writer.h | 9 +++++---- vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c | 3 ++- 8 files changed, 23 insertions(+), 9 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/base/ReadOptions.c b/vpr7_x2p/vpr/SRC/base/ReadOptions.c index 54c323f9c..d2f692774 100644 --- a/vpr7_x2p/vpr/SRC/base/ReadOptions.c +++ b/vpr7_x2p/vpr/SRC/base/ReadOptions.c @@ -560,7 +560,7 @@ ProcessOption(INP char **Args, INOUTP t_options * Options) { case OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS: return Args; case OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI: - return Args; + return ReadString(Args, &Options->fpga_verilog_simulation_ini_path); /* Xifan TANG: Bitstream generator */ case OT_FPGA_BITSTREAM_GENERATOR: return Args; diff --git a/vpr7_x2p/vpr/SRC/base/ReadOptions.h b/vpr7_x2p/vpr/SRC/base/ReadOptions.h index a637f5792..a242ba0b1 100644 --- a/vpr7_x2p/vpr/SRC/base/ReadOptions.h +++ b/vpr7_x2p/vpr/SRC/base/ReadOptions.h @@ -107,6 +107,7 @@ struct s_options { char* fpga_verilog_reference_benchmark_file; char* fpga_verilog_modelsim_ini_path; char* fpga_verilog_report_timing_path; + char* fpga_verilog_simulation_ini_path; /* Xifan TANG: Bitstream generator */ char* fpga_bitstream_file; }; diff --git a/vpr7_x2p/vpr/SRC/base/SetupVPR.c b/vpr7_x2p/vpr/SRC/base/SetupVPR.c index 1cb3fba67..56ec465d2 100644 --- a/vpr7_x2p/vpr/SRC/base/SetupVPR.c +++ b/vpr7_x2p/vpr/SRC/base/SetupVPR.c @@ -1186,6 +1186,7 @@ static void SetupSynVerilogOpts(t_options Options, if (Options.Count[OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI]) { syn_verilog_opts->print_simulation_ini = TRUE; + syn_verilog_opts->simulation_ini_path = my_strdup(Options.fpga_verilog_simulation_ini_path); } /* SynVerilog needs the input from spice modeling */ diff --git a/vpr7_x2p/vpr/SRC/base/vpr_api.c b/vpr7_x2p/vpr/SRC/base/vpr_api.c index 5148daa23..552a90b36 100644 --- a/vpr7_x2p/vpr/SRC/base/vpr_api.c +++ b/vpr7_x2p/vpr/SRC/base/vpr_api.c @@ -211,7 +211,7 @@ void vpr_print_usage(void) { vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_report_timing_rpt_path \n"); vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_sdc_pnr\n"); vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_sdc_analysis\n"); - vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_simulation_ini\n"); + vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_simulation_ini \n"); /* Xifan Tang: Bitstream generator */ vpr_printf(TIO_MESSAGE_INFO, "Bitstream Generator Options:\n"); vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_bitstream_generator\n"); diff --git a/vpr7_x2p/vpr/SRC/base/vpr_types.h b/vpr7_x2p/vpr/SRC/base/vpr_types.h index 95ae3784c..0c3491d8d 100755 --- a/vpr7_x2p/vpr/SRC/base/vpr_types.h +++ b/vpr7_x2p/vpr/SRC/base/vpr_types.h @@ -1282,6 +1282,7 @@ struct s_syn_verilog_opts { boolean print_sdc_pnr; boolean print_sdc_analysis; boolean print_simulation_ini; + char* simulation_ini_path; }; /* Xifan TANG: bitstream generator */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp index 93474da0b..795bdc999 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp @@ -22,12 +22,13 @@ * Top-level function to write an ini file which contains exchangeable * information, in order to interface different Verilog simulators ********************************************************************/ -void print_verilog_simulation_info(const int& num_operating_clock_cycles, +void print_verilog_simulation_info(const std::string& simulation_ini_filename, const std::string& parent_dir, const std::string& verilog_dir, const std::string& circuit_name, const std::string& src_dir, const size_t& num_program_clock_cycles, + const int& num_operating_clock_cycles, const float& prog_clock_freq, const float& op_clock_freq) { mINI::INIStructure ini; @@ -51,6 +52,14 @@ void print_verilog_simulation_info(const int& num_operating_clock_cycles, ini["SIMULATION_DECK"]["VERILOG_FILE1"] = std::string(defines_verilog_file_name); ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(circuit_name + "_include_netlists.v"); - mINI::INIFile file(parent_dir + "SimulationDeckInfo.ini"); + /* Use default name if user does not provide one */ + std::string ini_fname; + if (true == simulation_ini_filename.empty()) { + ini_fname = parent_dir + std::string("SimulationDeckInfo.ini"); + } else { + ini_fname = simulation_ini_filename; + } + + mINI::INIFile file(ini_fname); file.generate(ini, true); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h index 6be4b8f47..646b6ab5b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h @@ -3,12 +3,13 @@ #include -void print_verilog_simulation_info(const int& num_operating_clock_cycles, +void print_verilog_simulation_info(const std::string& simulation_ini_filename, const std::string& parent_dir, - const std::string& verilog_dir_formatted, - const std::string& chomped_circuit_name, - const std::string& src_dir_path, + const std::string& verilog_dir, + const std::string& circuit_name, + const std::string& src_dir, const size_t& num_program_clock_cycles, + const int& num_operating_clock_cycles, const float& prog_clock_freq, const float& op_clock_freq); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 192e3dc63..21a794a62 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -435,12 +435,13 @@ void vpr_fpga_verilog(ModuleManager& module_manager, if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_simulation_ini) { /* Print exchangeable files which contains simulation settings */ - print_verilog_simulation_info(Arch.spice->spice_params.meas_params.sim_num_clock_cycle, + print_verilog_simulation_info(std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path), std::string(format_dir_path(chomped_parent_dir)), std::string(msim_dir_path), std::string(chomped_circuit_name), std::string(src_dir_path), bitstream_manager.bits().size(), + Arch.spice->spice_params.meas_params.sim_num_clock_cycle, Arch.spice->spice_params.stimulate_params.prog_clock_freq, Arch.spice->spice_params.stimulate_params.op_clock_freq); } From 0852ef33c3bd2aa0a0b419e484baa62757f86c8c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 16:30:01 -0600 Subject: [PATCH 10/68] remove caching for deps --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9d68dc6f4..431f5a02c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ cache: - $TRAVIS_BUILD_DIR/ace2 - $TRAVIS_BUILD_DIR/libs - $HOME/.ccache - - $HOME/deps +# - $HOME/deps # Currently sudo is not required, NO ENV is used From fc164abd4951c760ceb04b212c34bb5734f6cd98 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 16:35:32 -0600 Subject: [PATCH 11/68] remove unused variable in sim info writer --- vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp | 1 - vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h | 1 - vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c | 1 - 3 files changed, 3 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp index 795bdc999..11ab48b74 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp @@ -24,7 +24,6 @@ ********************************************************************/ void print_verilog_simulation_info(const std::string& simulation_ini_filename, const std::string& parent_dir, - const std::string& verilog_dir, const std::string& circuit_name, const std::string& src_dir, const size_t& num_program_clock_cycles, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h index 646b6ab5b..9644e2a63 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.h @@ -5,7 +5,6 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, const std::string& parent_dir, - const std::string& verilog_dir, const std::string& circuit_name, const std::string& src_dir, const size_t& num_program_clock_cycles, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 21a794a62..c80264bf0 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -437,7 +437,6 @@ void vpr_fpga_verilog(ModuleManager& module_manager, /* Print exchangeable files which contains simulation settings */ print_verilog_simulation_info(std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path), std::string(format_dir_path(chomped_parent_dir)), - std::string(msim_dir_path), std::string(chomped_circuit_name), std::string(src_dir_path), bitstream_manager.bits().size(), From cb74d120e775807a02ccfcbebc0c422a6c613a47 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 17:31:05 -0600 Subject: [PATCH 12/68] shadow ini writer to help debugging --- vpr7_x2p/vpr/CMakeLists.txt | 8 ++--- .../verilog/simulation_info_writer.cpp | 11 +++++-- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 6 +++- .../verilog/verilog_formality_autodeck.c | 32 +++++++++---------- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/vpr7_x2p/vpr/CMakeLists.txt b/vpr7_x2p/vpr/CMakeLists.txt index 0fa11717e..81751b3d6 100644 --- a/vpr7_x2p/vpr/CMakeLists.txt +++ b/vpr7_x2p/vpr/CMakeLists.txt @@ -65,14 +65,14 @@ if (ENABLE_VPR_GRAPHIC_CXX_FLAG) libarchfpga X11 libvtrutil - readline - libini) + #libini + readline) else () target_link_libraries(libvpr libarchfpga libvtrutil - readline - libini) + #libini + readline) endif() #Create the executables diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp index 11ab48b74..f486ecf05 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp @@ -5,8 +5,8 @@ #include #include #include -#define MINI_CASE_SENSITIVE -#include "ini.h" +//#define MINI_CASE_SENSITIVE +//#include "ini.h" /* Include vpr structs*/ #include "util.h" @@ -30,7 +30,9 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, const int& num_operating_clock_cycles, const float& prog_clock_freq, const float& op_clock_freq) { + /* mINI::INIStructure ini; + */ // std::map units_map; // units_map['s']=1; // units_map['ms']=1E-3; // units_map['us']=1E-6; // units_map['ns']=1E-9; // units_map['ps']=1E-12; // units_map['fs']=1E-15; @@ -41,7 +43,7 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, 1. / prog_clock_freq, num_operating_clock_cycles, 1. / op_clock_freq); - + /* ini["SIMULATION_DECK"]["PROJECTNAME "] = "ModelSimProject"; ini["SIMULATION_DECK"]["BENCHMARK "] = circuit_name; ini["SIMULATION_DECK"]["TOP_TB"] = circuit_name + std::string("_top_formal_verification_random_tb"); @@ -50,6 +52,7 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, ini["SIMULATION_DECK"]["VERILOG_PATH "] = std::string(src_dir); ini["SIMULATION_DECK"]["VERILOG_FILE1"] = std::string(defines_verilog_file_name); ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(circuit_name + "_include_netlists.v"); + */ /* Use default name if user does not provide one */ std::string ini_fname; @@ -59,6 +62,8 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, ini_fname = simulation_ini_filename; } + /* mINI::INIFile file(ini_fname); file.generate(ini, true); + */ } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index c80264bf0..8991680a8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -418,11 +418,13 @@ void vpr_fpga_verilog(ModuleManager& module_manager, std::string(src_dir_path)); /* Output script for formality */ + /* write_formality_script(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, fm_dir_path, src_dir_path, chomped_circuit_name, *(Arch.spice)); + */ /* Print out top-level testbench using random vectors */ std::string random_top_testbench_file_path = std::string(src_dir_path) @@ -432,9 +434,10 @@ void vpr_fpga_verilog(ModuleManager& module_manager, std::string(src_dir_path), L_logical_blocks, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, Arch.spice->spice_params); } - + if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_simulation_ini) { /* Print exchangeable files which contains simulation settings */ + /* print_verilog_simulation_info(std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path), std::string(format_dir_path(chomped_parent_dir)), std::string(chomped_circuit_name), @@ -443,6 +446,7 @@ void vpr_fpga_verilog(ModuleManager& module_manager, Arch.spice->spice_params.meas_params.sim_num_clock_cycle, Arch.spice->spice_params.stimulate_params.prog_clock_freq, Arch.spice->spice_params.stimulate_params.op_clock_freq); + */ } if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_autocheck_top_testbench) { diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c index 33f587a75..1ffa58bea 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c @@ -10,8 +10,8 @@ #include #include #include -#define MINI_CASE_SENSITIVE -#include "ini.h" +//#define MINI_CASE_SENSITIVE +//#include "ini.h" /* Include vpr structs*/ #include "util.h" @@ -41,7 +41,7 @@ #include "verilog_routing.h" #include "verilog_tcl_utils.h" -mINI::INIStructure ini; +//mINI::INIStructure ini; static void searching_used_latch(FILE *fp, t_pb * pb, int pb_index, char* chomped_circuit_name, char* inst_name){ int i, j; @@ -80,7 +80,7 @@ static void searching_used_latch(FILE *fp, t_pb * pb, int pb_index, char* chompe inst_name, gen_verilog_one_pb_graph_node_full_name_in_hierarchy(node)); sprintf(INI_lbl, "%s_reg", pb->name); - ini["REGISTER_MATCH"][INI_lbl] = WriteBuffer; + //ini["REGISTER_MATCH"][INI_lbl] = WriteBuffer; } //free(tmp); //Looks like is the cause of a double free, once free executated next iteration as no value in tmp return; @@ -199,11 +199,11 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, /* Load Verilog benchmark as reference */ fprintf(fp, "read_verilog -container r -libname WORK -05 { %s }\n", benchmark_path); - ini["BENCHMARK_INFO"]["benchmark_netlist "] = benchmark_path; + //ini["BENCHMARK_INFO"]["benchmark_netlist "] = benchmark_path; /* Set reference top */ fprintf(fp, "set_top r:/WORK/%s\n", chomped_circuit_name); - ini["BENCHMARK_INFO"]["src_top_module "] = chomped_circuit_name; + //ini["BENCHMARK_INFO"]["src_top_module "] = chomped_circuit_name; /* Load generated verilog as implemnetation */ fprintf(fp, "read_verilog -container i -libname WORK -05 { "); @@ -213,7 +213,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, sprintf(WriteBuffer, "%s%s%s", src_dir_formatted, chomped_circuit_name, verilog_top_postfix); sprintf(INI_lbl, "impl_netlist_%02d",FileCounter++); - ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + //ini["FPGA_INFO"][INI_lbl] = WriteBuffer; fprintf(fp, "%s%s%s ", src_dir_formatted, chomped_circuit_name, @@ -221,7 +221,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, sprintf(WriteBuffer, "%s%s%s\n", src_dir_formatted, chomped_circuit_name, formal_verification_verilog_file_postfix); sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); - ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + //ini["FPGA_INFO"][INI_lbl] = WriteBuffer; init_include_user_defined_verilog_netlists(spice); // formality_include_user_defined_verilog_netlists(fp, spice); @@ -232,7 +232,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, assert(NULL != spice.include_netlists[i].path); fprintf(fp, "%s ", spice.include_netlists[i].path); sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); - ini["FPGA_INFO"][INI_lbl] = spice.include_netlists[i].path; + //ini["FPGA_INFO"][INI_lbl] = spice.include_netlists[i].path; spice.include_netlists[i].included = 1; } else { assert(1 == spice.include_netlists[i].included); @@ -246,7 +246,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, default_rr_dir_name, routing_verilog_file_name); sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); - ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + //ini["FPGA_INFO"][INI_lbl] = WriteBuffer; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fprintf(fp, "%s%s%s ", src_dir_formatted, default_lb_dir_name, @@ -255,7 +255,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, default_lb_dir_name, logic_block_verilog_file_name); sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); - ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + //ini["FPGA_INFO"][INI_lbl] = WriteBuffer; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fprintf(fp, "%s%s%s ", src_dir_formatted, default_submodule_dir_name, @@ -264,7 +264,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, default_submodule_dir_name, submodule_verilog_file_name); sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); - ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + //ini["FPGA_INFO"][INI_lbl] = WriteBuffer; fprintf(fp, "}\n"); /* Set implementation top */ @@ -272,7 +272,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, formal_verification_top_postfix)); sprintf(WriteBuffer, "%s", my_strcat(chomped_circuit_name, formal_verification_top_postfix)); - ini["FPGA_INFO"]["impl_top_module"] = WriteBuffer; + //ini["FPGA_INFO"]["impl_top_module"] = WriteBuffer; /* Run matching */ fprintf(fp, "match\n"); @@ -299,7 +299,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, my_strcat(logical_block[iblock].name, formal_verification_top_module_port_postfix)); sprintf(INI_lbl, "%s", original_output_name); - ini["PORT_MATCHING"][INI_lbl] = WriteBuffer; + //ini["PORT_MATCHING"][INI_lbl] = WriteBuffer; } } } @@ -309,7 +309,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, /* Script END */ fclose(fp); - mINI::INIFile file(my_strcat(formality_script_file_name,".ini")); - file.generate(ini, true); + //mINI::INIFile file(my_strcat(formality_script_file_name,".ini")); + //file.generate(ini, true); return; } From 644ca4f0a4cf2a46330f49cb0e0c7b63bf3e8c66 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 17:49:22 -0600 Subject: [PATCH 13/68] add vpr test run in Travis --- .travis/script.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis/script.sh b/.travis/script.sh index 7c5aab29b..cca32dcce 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -18,6 +18,8 @@ end_section "OpenFPGA.build" start_section "OpenFPGA.TaskTun" "${GREEN}..Running_Regression..${NC}" cd - +./vpr7_x2p/vpr/vpr ./openfpga_flow/arch/template/k4_N4_sram_chain_FC_behavioral_verilog_template.xml ./openfpga_flow/benchmarks/test_modes/k4_N4/K4N4_test_modes.blif --net_file ./openfpga_flow/benchmarks/test_modes/k4_N4/K4n4_test_vpr.net --place_file ./openfpga_flow/benchmarks/test_modes/k4_N4/K4n4_test_vpr.place --route_file ./openfpga_flow/benchmarks/test_modes/k4_N4/K4n4_test_vpr.route --full_stats --nodisp --activity_file ./openfpga_flow/benchmarks/test_modes/k4_N4/K4N4_test_modes.act --power --tech_properties ./openfpga_flow/tech/PTM_45nm/45nm.xml --fpga_x2p_compact_routing_hierarchy --fpga_verilog --fpga_verilog_dir ./verilog --fpga_verilog_print_autocheck_top_testbench K4n4_test_output_verilog.v --fpga_verilog_include_timing --fpga_verilog_explicit_mapping --fpga_verilog_include_signal_init --fpga_verilog_print_formal_verification_top_netlist --fpga_verilog_include_icarus_simulator --fpga_verilog_print_report_timing_tcl --fpga_verilog_print_sdc_pnr --fpga_verilog_print_user_defined_template --fpga_verilog_print_sdc_analysis --fpga_bitstream_generator --fpga_x2p_rename_illegal_port + echo -e "Testing single-mode architectures"; python3 openfpga_flow/scripts/run_fpga_task.py single_mode --debug --show_thread_logs #python3 openfpga_flow/scripts/run_fpga_task.py s298 From 3ad2a93539e943faf4f6a84e8ca428a2c0e984b7 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 18:20:25 -0600 Subject: [PATCH 14/68] start bring back ini writer bit by bit --- .travis/script.sh | 2 -- vpr7_x2p/vpr/CMakeLists.txt | 4 ++-- .../SRC/fpga_x2p/verilog/simulation_info_writer.cpp | 10 ++-------- vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c | 2 -- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/.travis/script.sh b/.travis/script.sh index cca32dcce..7c5aab29b 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -18,8 +18,6 @@ end_section "OpenFPGA.build" start_section "OpenFPGA.TaskTun" "${GREEN}..Running_Regression..${NC}" cd - -./vpr7_x2p/vpr/vpr ./openfpga_flow/arch/template/k4_N4_sram_chain_FC_behavioral_verilog_template.xml ./openfpga_flow/benchmarks/test_modes/k4_N4/K4N4_test_modes.blif --net_file ./openfpga_flow/benchmarks/test_modes/k4_N4/K4n4_test_vpr.net --place_file ./openfpga_flow/benchmarks/test_modes/k4_N4/K4n4_test_vpr.place --route_file ./openfpga_flow/benchmarks/test_modes/k4_N4/K4n4_test_vpr.route --full_stats --nodisp --activity_file ./openfpga_flow/benchmarks/test_modes/k4_N4/K4N4_test_modes.act --power --tech_properties ./openfpga_flow/tech/PTM_45nm/45nm.xml --fpga_x2p_compact_routing_hierarchy --fpga_verilog --fpga_verilog_dir ./verilog --fpga_verilog_print_autocheck_top_testbench K4n4_test_output_verilog.v --fpga_verilog_include_timing --fpga_verilog_explicit_mapping --fpga_verilog_include_signal_init --fpga_verilog_print_formal_verification_top_netlist --fpga_verilog_include_icarus_simulator --fpga_verilog_print_report_timing_tcl --fpga_verilog_print_sdc_pnr --fpga_verilog_print_user_defined_template --fpga_verilog_print_sdc_analysis --fpga_bitstream_generator --fpga_x2p_rename_illegal_port - echo -e "Testing single-mode architectures"; python3 openfpga_flow/scripts/run_fpga_task.py single_mode --debug --show_thread_logs #python3 openfpga_flow/scripts/run_fpga_task.py s298 diff --git a/vpr7_x2p/vpr/CMakeLists.txt b/vpr7_x2p/vpr/CMakeLists.txt index 81751b3d6..2e70b82fa 100644 --- a/vpr7_x2p/vpr/CMakeLists.txt +++ b/vpr7_x2p/vpr/CMakeLists.txt @@ -65,13 +65,13 @@ if (ENABLE_VPR_GRAPHIC_CXX_FLAG) libarchfpga X11 libvtrutil - #libini + libini readline) else () target_link_libraries(libvpr libarchfpga libvtrutil - #libini + libini readline) endif() diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp index f486ecf05..aa59a003b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp @@ -5,8 +5,8 @@ #include #include #include -//#define MINI_CASE_SENSITIVE -//#include "ini.h" +#define MINI_CASE_SENSITIVE +#include "ini.h" /* Include vpr structs*/ #include "util.h" @@ -30,9 +30,7 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, const int& num_operating_clock_cycles, const float& prog_clock_freq, const float& op_clock_freq) { - /* mINI::INIStructure ini; - */ // std::map units_map; // units_map['s']=1; // units_map['ms']=1E-3; // units_map['us']=1E-6; // units_map['ns']=1E-9; // units_map['ps']=1E-12; // units_map['fs']=1E-15; @@ -43,7 +41,6 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, 1. / prog_clock_freq, num_operating_clock_cycles, 1. / op_clock_freq); - /* ini["SIMULATION_DECK"]["PROJECTNAME "] = "ModelSimProject"; ini["SIMULATION_DECK"]["BENCHMARK "] = circuit_name; ini["SIMULATION_DECK"]["TOP_TB"] = circuit_name + std::string("_top_formal_verification_random_tb"); @@ -52,7 +49,6 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, ini["SIMULATION_DECK"]["VERILOG_PATH "] = std::string(src_dir); ini["SIMULATION_DECK"]["VERILOG_FILE1"] = std::string(defines_verilog_file_name); ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(circuit_name + "_include_netlists.v"); - */ /* Use default name if user does not provide one */ std::string ini_fname; @@ -62,8 +58,6 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, ini_fname = simulation_ini_filename; } - /* mINI::INIFile file(ini_fname); file.generate(ini, true); - */ } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 8991680a8..074fb557b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -437,7 +437,6 @@ void vpr_fpga_verilog(ModuleManager& module_manager, if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_simulation_ini) { /* Print exchangeable files which contains simulation settings */ - /* print_verilog_simulation_info(std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path), std::string(format_dir_path(chomped_parent_dir)), std::string(chomped_circuit_name), @@ -446,7 +445,6 @@ void vpr_fpga_verilog(ModuleManager& module_manager, Arch.spice->spice_params.meas_params.sim_num_clock_cycle, Arch.spice->spice_params.stimulate_params.prog_clock_freq, Arch.spice->spice_params.stimulate_params.op_clock_freq); - */ } if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_autocheck_top_testbench) { From c6817261244d2e177053ccaca64c52a8290ddff6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 18:33:05 -0600 Subject: [PATCH 15/68] try to enlarge write buffers in ini writer, but these codes should be fully reworked --- vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c | 2 -- .../vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 074fb557b..4c1c4a223 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -418,13 +418,11 @@ void vpr_fpga_verilog(ModuleManager& module_manager, std::string(src_dir_path)); /* Output script for formality */ - /* write_formality_script(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, fm_dir_path, src_dir_path, chomped_circuit_name, *(Arch.spice)); - */ /* Print out top-level testbench using random vectors */ std::string random_top_testbench_file_path = std::string(src_dir_path) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c index 1ffa58bea..7e28655fd 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c @@ -177,8 +177,8 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, char* formality_script_file_name = NULL; char* benchmark_path = NULL; char* original_output_name = NULL; - char WriteBuffer[200]; - char INI_lbl[20]; + char WriteBuffer[4096]; + char INI_lbl[4096]; /* int output_length; */ /* int pos; */ FILE* fp = NULL; From 05a830de1bd57635303262fb32fcd7277032f549 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 18:56:54 -0600 Subject: [PATCH 16/68] bring ini writer for formality scripts back --- .../verilog/verilog_formality_autodeck.c | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c index 7e28655fd..0052ab079 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formality_autodeck.c @@ -10,8 +10,8 @@ #include #include #include -//#define MINI_CASE_SENSITIVE -//#include "ini.h" +#define MINI_CASE_SENSITIVE +#include "ini.h" /* Include vpr structs*/ #include "util.h" @@ -41,7 +41,7 @@ #include "verilog_routing.h" #include "verilog_tcl_utils.h" -//mINI::INIStructure ini; +mINI::INIStructure ini; static void searching_used_latch(FILE *fp, t_pb * pb, int pb_index, char* chomped_circuit_name, char* inst_name){ int i, j; @@ -80,7 +80,7 @@ static void searching_used_latch(FILE *fp, t_pb * pb, int pb_index, char* chompe inst_name, gen_verilog_one_pb_graph_node_full_name_in_hierarchy(node)); sprintf(INI_lbl, "%s_reg", pb->name); - //ini["REGISTER_MATCH"][INI_lbl] = WriteBuffer; + ini["REGISTER_MATCH"][INI_lbl] = WriteBuffer; } //free(tmp); //Looks like is the cause of a double free, once free executated next iteration as no value in tmp return; @@ -199,11 +199,11 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, /* Load Verilog benchmark as reference */ fprintf(fp, "read_verilog -container r -libname WORK -05 { %s }\n", benchmark_path); - //ini["BENCHMARK_INFO"]["benchmark_netlist "] = benchmark_path; + ini["BENCHMARK_INFO"]["benchmark_netlist "] = benchmark_path; /* Set reference top */ fprintf(fp, "set_top r:/WORK/%s\n", chomped_circuit_name); - //ini["BENCHMARK_INFO"]["src_top_module "] = chomped_circuit_name; + ini["BENCHMARK_INFO"]["src_top_module "] = chomped_circuit_name; /* Load generated verilog as implemnetation */ fprintf(fp, "read_verilog -container i -libname WORK -05 { "); @@ -213,7 +213,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, sprintf(WriteBuffer, "%s%s%s", src_dir_formatted, chomped_circuit_name, verilog_top_postfix); sprintf(INI_lbl, "impl_netlist_%02d",FileCounter++); - //ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + ini["FPGA_INFO"][INI_lbl] = WriteBuffer; fprintf(fp, "%s%s%s ", src_dir_formatted, chomped_circuit_name, @@ -221,7 +221,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, sprintf(WriteBuffer, "%s%s%s\n", src_dir_formatted, chomped_circuit_name, formal_verification_verilog_file_postfix); sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); - //ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + ini["FPGA_INFO"][INI_lbl] = WriteBuffer; init_include_user_defined_verilog_netlists(spice); // formality_include_user_defined_verilog_netlists(fp, spice); @@ -232,7 +232,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, assert(NULL != spice.include_netlists[i].path); fprintf(fp, "%s ", spice.include_netlists[i].path); sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); - //ini["FPGA_INFO"][INI_lbl] = spice.include_netlists[i].path; + ini["FPGA_INFO"][INI_lbl] = spice.include_netlists[i].path; spice.include_netlists[i].included = 1; } else { assert(1 == spice.include_netlists[i].included); @@ -246,7 +246,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, default_rr_dir_name, routing_verilog_file_name); sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); - //ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + ini["FPGA_INFO"][INI_lbl] = WriteBuffer; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fprintf(fp, "%s%s%s ", src_dir_formatted, default_lb_dir_name, @@ -255,7 +255,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, default_lb_dir_name, logic_block_verilog_file_name); sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); - //ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + ini["FPGA_INFO"][INI_lbl] = WriteBuffer; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fprintf(fp, "%s%s%s ", src_dir_formatted, default_submodule_dir_name, @@ -264,7 +264,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, default_submodule_dir_name, submodule_verilog_file_name); sprintf(INI_lbl, "impl_netlist_%02d", FileCounter++); - //ini["FPGA_INFO"][INI_lbl] = WriteBuffer; + ini["FPGA_INFO"][INI_lbl] = WriteBuffer; fprintf(fp, "}\n"); /* Set implementation top */ @@ -272,7 +272,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, formal_verification_top_postfix)); sprintf(WriteBuffer, "%s", my_strcat(chomped_circuit_name, formal_verification_top_postfix)); - //ini["FPGA_INFO"]["impl_top_module"] = WriteBuffer; + ini["FPGA_INFO"]["impl_top_module"] = WriteBuffer; /* Run matching */ fprintf(fp, "match\n"); @@ -299,7 +299,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, my_strcat(logical_block[iblock].name, formal_verification_top_module_port_postfix)); sprintf(INI_lbl, "%s", original_output_name); - //ini["PORT_MATCHING"][INI_lbl] = WriteBuffer; + ini["PORT_MATCHING"][INI_lbl] = WriteBuffer; } } } @@ -309,7 +309,7 @@ void write_formality_script (t_syn_verilog_opts fpga_verilog_opts, /* Script END */ fclose(fp); - //mINI::INIFile file(my_strcat(formality_script_file_name,".ini")); - //file.generate(ini, true); + mINI::INIFile file(my_strcat(formality_script_file_name,".ini")); + file.generate(ini, true); return; } From dc241e6c03b778c278c5d1310295d61685db905e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Nov 2019 23:03:47 -0600 Subject: [PATCH 17/68] add explicit port mapping support in testbenches; remove dangling ports in benchmarks --- .../benchmarks/mcnc_big20/apex2/apex2.act | 1 - .../benchmarks/mcnc_big20/apex2/apex2.blif | 2 +- .../benchmarks/mcnc_big20/apex2/apex2.v | 3 +- .../tasks/mcnc_big20/config/task.conf | 23 ++++++----- .../verilog_formal_random_top_testbench.cpp | 40 +++++++++++++++---- 5 files changed, 48 insertions(+), 21 deletions(-) diff --git a/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.act b/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.act index 9bc344191..b91e3bfa6 100644 --- a/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.act +++ b/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.act @@ -13,7 +13,6 @@ i_11_ 0.495600 0.504600 i_12_ 0.502800 0.507600 i_13_ 0.494600 0.500600 i_14_ 0.504800 0.502800 -i_15_ 0.487600 0.495200 i_16_ 0.504000 0.505200 i_17_ 0.497400 0.512600 i_18_ 0.502200 0.502200 diff --git a/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.blif b/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.blif index 7ba78bd10..69f1a70c6 100644 --- a/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.blif +++ b/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.blif @@ -1,7 +1,7 @@ # Benchmark "apex2" written by ABC on Tue Mar 12 09:34:21 2019 .model apex2 .inputs i_0_ i_1_ i_2_ i_3_ i_4_ i_5_ i_6_ i_7_ i_8_ i_9_ i_10_ i_11_ i_12_ \ - i_13_ i_14_ i_15_ i_16_ i_17_ i_18_ i_19_ i_20_ i_21_ i_22_ i_23_ i_24_ \ + i_13_ i_14_ i_16_ i_17_ i_18_ i_19_ i_20_ i_21_ i_22_ i_23_ i_24_ \ i_25_ i_26_ i_27_ i_28_ i_29_ i_30_ i_31_ i_32_ i_33_ i_34_ i_35_ i_36_ \ i_37_ i_38_ .outputs o_0_ o_1_ o_2_ diff --git a/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.v b/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.v index b1e082d06..5a7719ec8 100644 --- a/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.v +++ b/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.v @@ -1,13 +1,12 @@ /* Generated by Yosys 0.8+133 (git sha1 2a2e0a4, gcc 7.3.0 -fPIC -Os) */ -module apex2(i_0_, i_1_, i_2_, i_3_, i_4_, i_5_, i_6_, i_7_, i_8_, i_9_, i_10_, i_11_, i_12_, i_13_, i_14_, i_15_, i_16_, i_17_, i_18_, i_19_, i_20_, i_21_, i_22_, i_23_, i_24_, i_25_, i_26_, i_27_, i_28_, i_29_, i_30_, i_31_, i_32_, i_33_, i_34_, i_35_, i_36_, i_37_, i_38_, o_0_, o_1_, o_2_); +module apex2(i_0_, i_1_, i_2_, i_3_, i_4_, i_5_, i_6_, i_7_, i_8_, i_9_, i_10_, i_11_, i_12_, i_13_, i_14_, i_16_, i_17_, i_18_, i_19_, i_20_, i_21_, i_22_, i_23_, i_24_, i_25_, i_26_, i_27_, i_28_, i_29_, i_30_, i_31_, i_32_, i_33_, i_34_, i_35_, i_36_, i_37_, i_38_, o_0_, o_1_, o_2_); input i_0_; input i_10_; input i_11_; input i_12_; input i_13_; input i_14_; - input i_15_; input i_16_; input i_17_; input i_18_; diff --git a/openfpga_flow/tasks/mcnc_big20/config/task.conf b/openfpga_flow/tasks/mcnc_big20/config/task.conf index 50d2402b8..ef31fe375 100644 --- a/openfpga_flow/tasks/mcnc_big20/config/task.conf +++ b/openfpga_flow/tasks/mcnc_big20/config/task.conf @@ -15,13 +15,16 @@ timeout_each_job = 20*60 fpga_flow=vpr_blif [ARCHITECTURES] -arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml +#arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml #arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k4_N4_sram_chain_FC_behavioral_verilog_template.xml -#arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml +arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml [BENCHMARKS] -bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/alu4/alu4.blif +# Pass +#bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/alu4/alu4.blif +# Fail, due to port does not match, i_15_ is dangling #bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.blif +# To be tested #bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/apex4/apex4.blif #bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/bigkey/bigkey.blif #bench4=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/clma/clma.blif @@ -34,8 +37,10 @@ bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/alu4/alu4.blif #bench11=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/frisc/frisc.blif #bench12=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/misex3/misex3.blif #bench13=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/pdc/pdc.blif -#bench14=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/s298/s298.blif # Pass -#bench15=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/s38417/s38417.blif # Multi-mode support fails to repack +# Pass +#bench14=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/s298/s298.blif +# Multi-mode support fails to repack +#bench15=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/s38417/s38417.blif #bench16=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/s38584/s38584.blif #bench17=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/seq/seq.blif #bench18=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/spla/spla.blif @@ -147,10 +152,10 @@ vpr_fpga_verilog_include_signal_init= vpr_fpga_verilog_print_autocheck_top_testbench= vpr_fpga_bitstream_generator= vpr_fpga_verilog_print_user_defined_template= -vpr_fpga_verilog_print_report_timing_tcl= -vpr_fpga_verilog_print_sdc_pnr= -vpr_fpga_verilog_print_sdc_analysis= +#vpr_fpga_verilog_print_report_timing_tcl= +#vpr_fpga_verilog_print_sdc_pnr= +#vpr_fpga_verilog_print_sdc_analysis= vpr_fpga_verilog_explicit_mapping= vpr_fpga_x2p_compact_routing_hierarchy= -end_flow_with_test= +#end_flow_with_test= diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp index 4277487ea..9f08f33f6 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp @@ -182,8 +182,11 @@ static void print_verilog_random_testbench_instance(std::fstream& fp, const std::string& module_name, const std::string& instance_name, + const std::string& module_input_port_postfix, + const std::string& module_output_port_postfix, const std::string& output_port_postfix, - const std::vector& L_logical_blocks) { + const std::vector& L_logical_blocks, + const bool& use_explicit_port_map) { /* Validate the file stream */ check_file_handler(fp); @@ -202,10 +205,24 @@ void print_verilog_random_testbench_instance(std::fstream& fp, } /* Input port follows the logical block name while output port requires a special postfix */ if (VPACK_INPAD == lb.type){ - fp << "\t\t" << std::string(lb.name); + fp << "\t\t"; + if (true == use_explicit_port_map) { + fp << "." << std::string(lb.name) << module_input_port_postfix << "("; + } + fp << std::string(lb.name); + if (true == use_explicit_port_map) { + fp << ")"; + } } else { VTR_ASSERT_SAFE(VPACK_OUTPAD == lb.type); - fp << "\t\t" << std::string(lb.name) << output_port_postfix; + fp << "\t\t"; + if (true == use_explicit_port_map) { + fp << "." << std::string(lb.name) << module_output_port_postfix << "("; + } + fp << std::string(lb.name) << output_port_postfix; + if (true == use_explicit_port_map) { + fp << ")"; + } } /* Update the counter */ port_counter++; @@ -213,8 +230,6 @@ void print_verilog_random_testbench_instance(std::fstream& fp, fp << "\t);" << std::endl; } - - /******************************************************************** * Instanciate the input benchmark module *******************************************************************/ @@ -230,9 +245,15 @@ void print_verilog_top_random_testbench_benchmark_instance(std::fstream& fp, print_verilog_comment(fp, std::string("----- Reference Benchmark Instanication -------")); + /* Do NOT use explicit port mapping here: + * VPR added a prefix of "out_" to the output ports of input benchmark + */ print_verilog_random_testbench_instance(fp, reference_verilog_top_name, std::string(BENCHMARK_INSTANCE_NAME), - std::string(BENCHMARK_PORT_POSTFIX), L_logical_blocks); + std::string(), + std::string(), + std::string(BENCHMARK_PORT_POSTFIX), L_logical_blocks, + false); print_verilog_comment(fp, std::string("----- End reference Benchmark Instanication -------")); @@ -389,10 +410,13 @@ void print_verilog_random_testbench_fpga_instance(std::fstream& fp, print_verilog_comment(fp, std::string("----- FPGA fabric instanciation -------")); - + /* Always use explicit port mapping */ print_verilog_random_testbench_instance(fp, std::string(circuit_name + std::string(formal_verification_top_postfix)), std::string(FPGA_INSTANCE_NAME), - std::string(FPGA_PORT_POSTFIX), L_logical_blocks); + std::string(formal_verification_top_module_port_postfix), + std::string(formal_verification_top_module_port_postfix), + std::string(FPGA_PORT_POSTFIX), L_logical_blocks, + true); print_verilog_comment(fp, std::string("----- End FPGA Fabric Instanication -------")); From 0ec465d4e195f6ba58cf479110a05f4940b1437c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 3 Nov 2019 17:41:29 -0700 Subject: [PATCH 18/68] refactoring auto-check top Verilog testbench --- .../tasks/mcnc_big20/config/task.conf | 7 +- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 46 +++-- .../verilog/verilog_autocheck_top_testbench.c | 2 +- .../verilog_autocheck_top_testbench.cpp | 89 --------- .../verilog/verilog_autocheck_top_testbench.h | 23 +-- .../verilog_formal_random_top_testbench.cpp | 80 ++------ .../verilog/verilog_preconfig_top_module.cpp | 121 +----------- .../verilog/verilog_testbench_utils.cpp | 178 ++++++++++++++++++ .../verilog/verilog_testbench_utils.h | 35 ++++ .../fpga_x2p/verilog/verilog_top_testbench.c | 2 +- .../fpga_x2p/verilog/verilog_top_testbench.h | 28 ++- .../fpga_x2p/verilog/verilog_writer_utils.cpp | 130 +++++++++++++ .../fpga_x2p/verilog/verilog_writer_utils.h | 21 +++ 13 files changed, 447 insertions(+), 315 deletions(-) delete mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h diff --git a/openfpga_flow/tasks/mcnc_big20/config/task.conf b/openfpga_flow/tasks/mcnc_big20/config/task.conf index ef31fe375..05961d06b 100644 --- a/openfpga_flow/tasks/mcnc_big20/config/task.conf +++ b/openfpga_flow/tasks/mcnc_big20/config/task.conf @@ -22,11 +22,12 @@ arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_til [BENCHMARKS] # Pass #bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/alu4/alu4.blif -# Fail, due to port does not match, i_15_ is dangling +# Pass, but port does not match, i_15_ is dangling #bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.blif -# To be tested +# Pass #bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/apex4/apex4.blif -#bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/bigkey/bigkey.blif +bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/bigkey/bigkey.blif +# To be tested #bench4=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/clma/clma.blif #bench5=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/des/des.blif #bench6=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/diffeq/diffeq.blif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 4c1c4a223..73270144c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -152,14 +152,10 @@ void vpr_fpga_verilog(ModuleManager& module_manager, char* fm_dir_path = NULL; char* top_netlist_file = NULL; char* top_netlist_path = NULL; - char* top_testbench_file_name = NULL; - char* top_testbench_file_path = NULL; char* blif_testbench_file_name = NULL; char* blif_testbench_file_path = NULL; char* bitstream_file_name = NULL; char* bitstream_file_path = NULL; - char* autocheck_top_testbench_file_name = NULL; - char* autocheck_top_testbench_file_path = NULL; char* chomped_parent_dir = NULL; char* chomped_circuit_name = NULL; @@ -390,19 +386,31 @@ void vpr_fpga_verilog(ModuleManager& module_manager, my_free(bitstream_file_path); } - /* dump verilog testbench only for top-level: ONLY valid when bitstream is generated! */ - if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_top_testbench) { - top_testbench_file_name = my_strcat(chomped_circuit_name, top_testbench_verilog_file_postfix); - top_testbench_file_path = my_strcat(src_dir_path, top_testbench_file_name); - dump_verilog_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, top_testbench_file_path, - src_dir_path, *(Arch.spice)); - /* Free */ - my_free(top_testbench_file_name); - my_free(top_testbench_file_path); - } - + /* Collect global ports from the circuit library + * TODO: move outside this function + */ std::vector global_ports = find_circuit_library_global_ports(Arch.spice->circuit_lib); + /* dump verilog testbench only for top-level: ONLY valid when bitstream is generated! */ + if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_top_testbench) { + std::string top_testbench_file_path = std::string(src_dir_path) + + std::string(chomped_circuit_name) + + std::string(top_testbench_verilog_file_postfix); + /* TODO: this is an old function, to be shadowed */ + dump_verilog_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, top_testbench_file_path.c_str(), + src_dir_path, *(Arch.spice)); + /* TODO: new function: to be tested */ + print_verilog_top_testbench(module_manager, bitstream_manager, fabric_bitstream, + sram_verilog_orgz_info->type, + Arch.spice->circuit_lib, global_ports, + L_logical_blocks, device_size, L_grids, L_blocks, + std::string(chomped_circuit_name), + std::string(top_testbench_file_path + std::string(".bak")), + std::string(src_dir_path), + std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file), + Arch.spice->spice_params); + } + if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_formal_verification_top_netlist) { std::string formal_verification_top_netlist_file_path = std::string(src_dir_path) + std::string(chomped_circuit_name) @@ -446,10 +454,12 @@ void vpr_fpga_verilog(ModuleManager& module_manager, } if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_autocheck_top_testbench) { - autocheck_top_testbench_file_name = my_strcat(chomped_circuit_name, autocheck_top_testbench_verilog_file_postfix); - autocheck_top_testbench_file_path = my_strcat(src_dir_path, autocheck_top_testbench_file_name); + std::string autocheck_top_testbench_file_path = std::string(src_dir_path) + + std::string(chomped_circuit_name) + + std::string(autocheck_top_testbench_verilog_file_postfix); + /* TODO: this is an old function, to be shadowed */ dump_verilog_autocheck_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, - autocheck_top_testbench_file_path, src_dir_path, + autocheck_top_testbench_file_path.c_str(), src_dir_path, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, *(Arch.spice)); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.c index e3c234c08..2cb7bf089 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.c @@ -348,7 +348,7 @@ void dump_verilog_top_auto_testbench_check(FILE* fp){ void dump_verilog_autocheck_top_testbench(t_sram_orgz_info* cur_sram_orgz_info, char* circuit_name, - char* top_netlist_name, + const char* top_netlist_name, char* verilog_dir_path, t_syn_verilog_opts fpga_verilog_opts, t_spice verilog) { diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.cpp deleted file mode 100644 index 6f60b4d21..000000000 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/******************************************************************** - * This file includes functions that are used to create - * an auto-check top-level testbench for a FPGA fabric - *******************************************************************/ -#include -#include - -#include "vtr_assert.h" - -#include "fpga_x2p_utils.h" - -#include "verilog_writer_utils.h" - -#include "verilog_autocheck_top_testbench.h" - -/******************************************************************** - * The top-level function to generate a testbench, in order to verify: - * 1. Configuration phase of the FPGA fabric, where the bitstream is - * loaded to the configuration protocol of the FPGA fabric - * 2. Operating phase of the FPGA fabric, where input stimuli are - * fed to the I/Os of the FPGA fabric - *******************************************************************/ -void print_verilog_autocheck_top_testbench(const ModuleManager& module_manager, - const BitstreamManager& bitstream_manager, - const CircuitLibrary& circuit_lib, - const std::vector& global_ports, - const std::vector& L_logical_blocks, - const vtr::Point& device_size, - const std::vector>& L_grids, - const std::vector& L_blocks, - const std::string& circuit_name, - const std::string& verilog_fname, - const std::string& verilog_dir, - const t_syn_verilog_opts& fpga_verilog_opts, - const t_spice_params& simulation_parameters) { - vpr_printf(TIO_MESSAGE_INFO, - "Writing Autocheck Testbench for FPGA Top-level Verilog netlist for %s...", - circuit_name.c_str()); - - /* Start time count */ - clock_t t_start = clock(); - - /* Create the file stream */ - std::fstream fp; - fp.open(verilog_fname, std::fstream::out | std::fstream::trunc); - - /* Validate the file stream */ - check_file_handler(fp); - - /* Generate a brief description on the Verilog file*/ - std::string title = std::string("FPGA Verilog Testbench for Top-level netlist of Design: ") + circuit_name; - print_verilog_file_header(fp, title); - - /* Print preprocessing flags and external netlists */ - print_verilog_include_defines_preproc_file(fp, verilog_dir); - - /* Start of testbench */ - //dump_verilog_top_auto_testbench_ports(fp, cur_sram_orgz_info, circuit_name, fpga_verilog_opts); - - /* Call defined top-level module */ - //dump_verilog_top_testbench_call_top_module(cur_sram_orgz_info, fp, - // circuit_name, is_explicit_mapping); - - /* Call defined benchmark */ - //dump_verilog_top_auto_testbench_call_benchmark(fp, circuit_name); - - /* Add stimuli for reset, set, clock and iopad signals */ - //dump_verilog_top_testbench_stimuli(cur_sram_orgz_info, fp, verilog); - - /* Add output autocheck */ - //dump_verilog_top_auto_testbench_check(fp); - - /* Add Icarus requirement */ - //dump_verilog_timeout_and_vcd(fp, circuit_name , verilog, cur_sram_orgz_info); - - /* Testbench ends*/ - //fprintf(fp, "endmodule\n"); - - /* Close the file stream */ - 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); -} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.h index a34deb5da..4b9f09d62 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_autocheck_top_testbench.h @@ -1,33 +1,12 @@ #ifndef VERILOG_AUTOCHECK_TOP_TESTBENCH_H #define VERILOG_AUTOCHECK_TOP_TESTBENCH_H -#include -#include -#include "module_manager.h" -#include "bitstream_manager.h" -#include "circuit_library.h" void dump_verilog_autocheck_top_testbench(t_sram_orgz_info* cur_sram_orgz_info, char* circuit_name, - char* top_netlist_name, + const char* top_netlist_name, char* verilog_dir_path, t_syn_verilog_opts fpga_verilog_opts, t_spice verilog); -/* -void print_verilog_autocheck_top_testbench(const ModuleManager& module_manager, - const BitstreamManager& bitstream_manager, - const CircuitLibrary& circuit_lib, - const std::vector& global_ports, - const std::vector& L_logical_blocks, - const vtr::Point& device_size, - const std::vector>& L_grids, - const std::vector& L_blocks, - const std::string& circuit_name, - const std::string& verilog_fname, - const std::string& verilog_dir, - const t_syn_verilog_opts& fpga_verilog_opts, - const t_spice_params& simulation_parameters); -*/ - #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp index 9f08f33f6..78f14b07b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp @@ -24,6 +24,7 @@ /* Include FPGA Verilog headers*/ #include "verilog_global.h" #include "verilog_writer_utils.h" +#include "verilog_testbench_utils.h" #include "verilog_formal_random_top_testbench.h" /******************************************************************** @@ -175,61 +176,6 @@ void print_verilog_top_random_testbench_ports(std::fstream& fp, fp << std::endl; } -/******************************************************************** - * Instanciate the FPGA fabric module - *******************************************************************/ -static -void print_verilog_random_testbench_instance(std::fstream& fp, - const std::string& module_name, - const std::string& instance_name, - const std::string& module_input_port_postfix, - const std::string& module_output_port_postfix, - const std::string& output_port_postfix, - const std::vector& L_logical_blocks, - const bool& use_explicit_port_map) { - - /* Validate the file stream */ - check_file_handler(fp); - - fp << "\t" << module_name << " " << instance_name << "(" << std::endl; - - size_t port_counter = 0; - for (const t_logical_block& lb : L_logical_blocks) { - /* Bypass non-I/O logical blocks ! */ - if ( (VPACK_INPAD != lb.type) && (VPACK_OUTPAD != lb.type) ) { - continue; - } - /* The first port does not need a comma */ - if(0 < port_counter){ - fp << "," << std::endl; - } - /* Input port follows the logical block name while output port requires a special postfix */ - if (VPACK_INPAD == lb.type){ - fp << "\t\t"; - if (true == use_explicit_port_map) { - fp << "." << std::string(lb.name) << module_input_port_postfix << "("; - } - fp << std::string(lb.name); - if (true == use_explicit_port_map) { - fp << ")"; - } - } else { - VTR_ASSERT_SAFE(VPACK_OUTPAD == lb.type); - fp << "\t\t"; - if (true == use_explicit_port_map) { - fp << "." << std::string(lb.name) << module_output_port_postfix << "("; - } - fp << std::string(lb.name) << output_port_postfix; - if (true == use_explicit_port_map) { - fp << ")"; - } - } - /* Update the counter */ - port_counter++; - } - fp << "\t);" << std::endl; -} - /******************************************************************** * Instanciate the input benchmark module *******************************************************************/ @@ -248,12 +194,12 @@ void print_verilog_top_random_testbench_benchmark_instance(std::fstream& fp, /* Do NOT use explicit port mapping here: * VPR added a prefix of "out_" to the output ports of input benchmark */ - print_verilog_random_testbench_instance(fp, reference_verilog_top_name, - std::string(BENCHMARK_INSTANCE_NAME), - std::string(), - std::string(), - std::string(BENCHMARK_PORT_POSTFIX), L_logical_blocks, - false); + print_verilog_testbench_benchmark_instance(fp, reference_verilog_top_name, + std::string(BENCHMARK_INSTANCE_NAME), + std::string(), + std::string(), + std::string(BENCHMARK_PORT_POSTFIX), L_logical_blocks, + false); print_verilog_comment(fp, std::string("----- End reference Benchmark Instanication -------")); @@ -411,12 +357,12 @@ void print_verilog_random_testbench_fpga_instance(std::fstream& fp, print_verilog_comment(fp, std::string("----- FPGA fabric instanciation -------")); /* Always use explicit port mapping */ - print_verilog_random_testbench_instance(fp, std::string(circuit_name + std::string(formal_verification_top_postfix)), - std::string(FPGA_INSTANCE_NAME), - std::string(formal_verification_top_module_port_postfix), - std::string(formal_verification_top_module_port_postfix), - std::string(FPGA_PORT_POSTFIX), L_logical_blocks, - true); + print_verilog_testbench_benchmark_instance(fp, std::string(circuit_name + std::string(formal_verification_top_postfix)), + std::string(FPGA_INSTANCE_NAME), + std::string(formal_verification_top_module_port_postfix), + std::string(formal_verification_top_module_port_postfix), + std::string(FPGA_PORT_POSTFIX), L_logical_blocks, + true); print_verilog_comment(fp, std::string("----- End FPGA Fabric Instanication -------")); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp index 14ca60752..6f0b7b43e 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp @@ -17,6 +17,7 @@ #include "verilog_global.h" #include "verilog_writer_utils.h" +#include "verilog_testbench_utils.h" #include "verilog_preconfig_top_module.h" /******************************************************************** @@ -89,31 +90,6 @@ void print_verilog_preconfig_top_module_internal_wires(std::fstream& fp, fp << std::endl; } -/******************************************************************** - * Print an instance of the FPGA top-level module - *******************************************************************/ -static -void print_verilog_preconfig_top_instance(std::fstream& fp, - const ModuleManager& module_manager, - const ModuleId& top_module) { - /* Validate the file stream */ - check_file_handler(fp); - - /* Include defined top-level module */ - print_verilog_comment(fp, std::string("----- FPGA top-level module to be capsulated -----")); - - /* Create an empty port-to-port name mapping, because we use default names */ - std::map port2port_name_map; - - /* Use explicit port mapping for a clean instanciation */ - print_verilog_module_instance(fp, module_manager, top_module, - std::string(formal_verification_top_module_uut_name), - port2port_name_map, true); - - /* Add an empty line as a splitter */ - fp << std::endl; -} - /******************************************************************** * Connect global ports of FPGA top module to constants except: * 1. operating clock, which should be wired to the clock port of @@ -180,90 +156,6 @@ void print_verilog_preconfig_top_module_connect_global_ports(std::fstream& fp, fp << std::endl; } -/******************************************************************** - * This function adds stimuli to I/Os of FPGA fabric - * 1. For mapped I/Os, this function will wire them to the input ports - * of the pre-configured FPGA top module - * 2. For unmapped I/Os, this function will assign a constant value - * by default - *******************************************************************/ -static -void print_verilog_preconfig_top_module_connect_ios(std::fstream& fp, - const ModuleManager& module_manager, - const ModuleId& top_module, - const std::vector& L_logical_blocks, - const vtr::Point& device_size, - const std::vector>& L_grids, - const std::vector& L_blocks) { - /* Validate the file stream */ - check_file_handler(fp); - - /* In this function, we support only 1 type of I/Os */ - VTR_ASSERT(1 == module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT).size()); - BasicPort module_io_port = module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)[0]; - - /* Keep tracking which I/Os have been used */ - std::vector io_used(module_io_port.get_width(), false); - - /* See if this I/O should be wired to a benchmark input/output */ - /* Add signals from blif benchmark and short-wire them to FPGA I/O PADs - * This brings convenience to checking functionality - */ - print_verilog_comment(fp, std::string("----- Link BLIF Benchmark I/Os to FPGA I/Os -----")); - for (const t_logical_block& io_lb : L_logical_blocks) { - /* We only care I/O logical blocks !*/ - if ( (VPACK_INPAD != io_lb.type) && (VPACK_OUTPAD != io_lb.type) ) { - continue; - } - - /* Find the index of the mapped GPIO in top-level FPGA fabric */ - size_t io_index = find_benchmark_io_index(io_lb, device_size, L_grids, L_blocks); - - /* Ensure that IO index is in range */ - BasicPort module_mapped_io_port = module_io_port; - /* Set the port pin index */ - VTR_ASSERT(io_index < module_mapped_io_port.get_width()); - module_mapped_io_port.set_width(io_index, io_index); - - /* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always has a size of 1 */ - BasicPort benchmark_io_port(std::string(std::string(io_lb.name)+ std::string(formal_verification_top_module_port_postfix)), 1); - - print_verilog_comment(fp, std::string("----- Blif Benchmark inout " + std::string(io_lb.name) + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----")); - if (VPACK_INPAD == io_lb.type) { - print_verilog_wire_connection(fp, module_mapped_io_port, benchmark_io_port, false); - } else { - VTR_ASSERT(VPACK_OUTPAD == io_lb.type); - print_verilog_wire_connection(fp, benchmark_io_port, module_mapped_io_port, false); - } - - /* Mark this I/O has been used/wired */ - io_used[io_index] = true; - } - - /* Add an empty line as a splitter */ - fp << std::endl; - - /* Wire the unused iopads to a constant */ - print_verilog_comment(fp, std::string("----- Wire unused FPGA I/Os to constants -----")); - for (size_t io_index = 0; io_index < io_used.size(); ++io_index) { - /* Bypass used iopads */ - if (true == io_used[io_index]) { - continue; - } - - /* Wire to a contant */ - BasicPort module_unused_io_port = module_io_port; - /* Set the port pin index */ - module_unused_io_port.set_width(io_index, io_index); - - std::vector default_values(module_unused_io_port.get_width(), verilog_default_signal_init_value); - print_verilog_wire_constant_values(fp, module_unused_io_port, default_values); - } - - /* Add an empty line as a splitter */ - fp << std::endl; -} - /******************************************************************** * Impose the bitstream on the configuration memories * This function uses 'assign' syntax to impost the bitstream at mem port @@ -514,7 +406,8 @@ void print_verilog_preconfig_top_module(const ModuleManager& module_manager, print_verilog_preconfig_top_module_internal_wires(fp, module_manager, top_module); /* Instanciate FPGA top-level module */ - print_verilog_preconfig_top_instance(fp, module_manager, top_module); + print_verilog_testbench_fpga_instance(fp, module_manager, top_module, + std::string(formal_verification_top_module_uut_name)); /* Find clock ports in benchmark */ std::vector benchmark_clock_port_names = find_benchmark_clock_port_name(L_logical_blocks); @@ -525,9 +418,11 @@ void print_verilog_preconfig_top_module(const ModuleManager& module_manager, benchmark_clock_port_names); /* Connect I/Os to benchmark I/Os or constant driver */ - print_verilog_preconfig_top_module_connect_ios(fp, module_manager, top_module, - L_logical_blocks, device_size, L_grids, - L_blocks); + print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module, + L_logical_blocks, device_size, L_grids, + L_blocks, + std::string(formal_verification_top_module_port_postfix), + (size_t)verilog_default_signal_init_value); /* Assign FPGA internal SRAM/Memory ports to bitstream values */ print_verilog_preconfig_top_module_load_bitstream(fp, module_manager, top_module, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp new file mode 100644 index 000000000..c1784ab26 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp @@ -0,0 +1,178 @@ +/******************************************************************** + * This file includes most utilized functions that are used to create + * Verilog testbenches + * + * Note: please do NOT use global variables in this file + * so that we can make it free to use anywhere + *******************************************************************/ +#include "vtr_assert.h" +#include "device_port.h" + +#include "fpga_x2p_utils.h" +#include "fpga_x2p_benchmark_utils.h" + +#include "verilog_writer_utils.h" +#include "verilog_testbench_utils.h" + +/******************************************************************** + * Print an instance of the FPGA top-level module + *******************************************************************/ +void print_verilog_testbench_fpga_instance(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const std::string& top_instance_name) { + /* Validate the file stream */ + check_file_handler(fp); + + /* Include defined top-level module */ + print_verilog_comment(fp, std::string("----- FPGA top-level module to be capsulated -----")); + + /* Create an empty port-to-port name mapping, because we use default names */ + std::map port2port_name_map; + + /* Use explicit port mapping for a clean instanciation */ + print_verilog_module_instance(fp, module_manager, top_module, + top_instance_name, + port2port_name_map, true); + + /* Add an empty line as a splitter */ + fp << std::endl; +} + +/******************************************************************** + * Instanciate the input benchmark module + *******************************************************************/ +void print_verilog_testbench_benchmark_instance(std::fstream& fp, + const std::string& module_name, + const std::string& instance_name, + const std::string& module_input_port_postfix, + const std::string& module_output_port_postfix, + const std::string& output_port_postfix, + const std::vector& L_logical_blocks, + const bool& use_explicit_port_map) { + /* Validate the file stream */ + check_file_handler(fp); + + fp << "\t" << module_name << " " << instance_name << "(" << std::endl; + + size_t port_counter = 0; + for (const t_logical_block& lb : L_logical_blocks) { + /* Bypass non-I/O logical blocks ! */ + if ( (VPACK_INPAD != lb.type) && (VPACK_OUTPAD != lb.type) ) { + continue; + } + /* The first port does not need a comma */ + if(0 < port_counter){ + fp << "," << std::endl; + } + /* Input port follows the logical block name while output port requires a special postfix */ + if (VPACK_INPAD == lb.type){ + fp << "\t\t"; + if (true == use_explicit_port_map) { + fp << "." << std::string(lb.name) << module_input_port_postfix << "("; + } + fp << std::string(lb.name); + if (true == use_explicit_port_map) { + fp << ")"; + } + } else { + VTR_ASSERT_SAFE(VPACK_OUTPAD == lb.type); + fp << "\t\t"; + if (true == use_explicit_port_map) { + fp << "." << std::string(lb.name) << module_output_port_postfix << "("; + } + fp << std::string(lb.name) << output_port_postfix; + if (true == use_explicit_port_map) { + fp << ")"; + } + } + /* Update the counter */ + port_counter++; + } + fp << "\t);" << std::endl; +} + +/******************************************************************** + * This function adds stimuli to I/Os of FPGA fabric + * 1. For mapped I/Os, this function will wire them to the input ports + * of the pre-configured FPGA top module + * 2. For unmapped I/Os, this function will assign a constant value + * by default + *******************************************************************/ +void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const std::vector& L_logical_blocks, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, + const std::string& io_port_name_postfix, + const size_t& unused_io_value) { + /* Validate the file stream */ + check_file_handler(fp); + + /* In this function, we support only 1 type of I/Os */ + VTR_ASSERT(1 == module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT).size()); + BasicPort module_io_port = module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)[0]; + + /* Keep tracking which I/Os have been used */ + std::vector io_used(module_io_port.get_width(), false); + + /* See if this I/O should be wired to a benchmark input/output */ + /* Add signals from blif benchmark and short-wire them to FPGA I/O PADs + * This brings convenience to checking functionality + */ + print_verilog_comment(fp, std::string("----- Link BLIF Benchmark I/Os to FPGA I/Os -----")); + for (const t_logical_block& io_lb : L_logical_blocks) { + /* We only care I/O logical blocks !*/ + if ( (VPACK_INPAD != io_lb.type) && (VPACK_OUTPAD != io_lb.type) ) { + continue; + } + + /* Find the index of the mapped GPIO in top-level FPGA fabric */ + size_t io_index = find_benchmark_io_index(io_lb, device_size, L_grids, L_blocks); + + /* Ensure that IO index is in range */ + BasicPort module_mapped_io_port = module_io_port; + /* Set the port pin index */ + VTR_ASSERT(io_index < module_mapped_io_port.get_width()); + module_mapped_io_port.set_width(io_index, io_index); + + /* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always has a size of 1 */ + BasicPort benchmark_io_port(std::string(std::string(io_lb.name)+ io_port_name_postfix), 1); + + print_verilog_comment(fp, std::string("----- Blif Benchmark inout " + std::string(io_lb.name) + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----")); + if (VPACK_INPAD == io_lb.type) { + print_verilog_wire_connection(fp, module_mapped_io_port, benchmark_io_port, false); + } else { + VTR_ASSERT(VPACK_OUTPAD == io_lb.type); + print_verilog_wire_connection(fp, benchmark_io_port, module_mapped_io_port, false); + } + + /* Mark this I/O has been used/wired */ + io_used[io_index] = true; + } + + /* Add an empty line as a splitter */ + fp << std::endl; + + /* Wire the unused iopads to a constant */ + print_verilog_comment(fp, std::string("----- Wire unused FPGA I/Os to constants -----")); + for (size_t io_index = 0; io_index < io_used.size(); ++io_index) { + /* Bypass used iopads */ + if (true == io_used[io_index]) { + continue; + } + + /* Wire to a contant */ + BasicPort module_unused_io_port = module_io_port; + /* Set the port pin index */ + module_unused_io_port.set_width(io_index, io_index); + + std::vector default_values(module_unused_io_port.get_width(), unused_io_value); + print_verilog_wire_constant_values(fp, module_unused_io_port, default_values); + } + + /* Add an empty line as a splitter */ + fp << std::endl; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h new file mode 100644 index 000000000..ffa7411eb --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h @@ -0,0 +1,35 @@ +#ifndef VERILOG_TESTBENCH_UTILS_H +#define VERILOG_TESTBENCH_UTILS_H + +/* Include header files which are used in the function declaration */ +#include +#include +#include +#include "module_manager.h" +#include "vpr_types.h" + +void print_verilog_testbench_fpga_instance(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const std::string& top_instance_name); + +void print_verilog_testbench_benchmark_instance(std::fstream& fp, + const std::string& module_name, + const std::string& instance_name, + const std::string& module_input_port_postfix, + const std::string& module_output_port_postfix, + const std::string& output_port_postfix, + const std::vector& L_logical_blocks, + const bool& use_explicit_port_map); + +void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const std::vector& L_logical_blocks, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, + const std::string& io_port_name_postfix, + const size_t& unused_io_value); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.c index 6671ec6e4..b1c628c99 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.c @@ -1329,7 +1329,7 @@ void dump_verilog_input_blif_testbench_stimuli(FILE* fp, */ void dump_verilog_top_testbench(t_sram_orgz_info* cur_sram_orgz_info, char* circuit_name, - char* top_netlist_name, + const char* top_netlist_name, char* verilog_dir_path, t_spice verilog) { FILE* fp = NULL; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.h index caf107479..c570b6293 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.h @@ -1,3 +1,27 @@ +#ifndef VERILOG_TOP_TESTBENCH +#define VERILOG_TOP_TESTBENCH + +#include +#include +#include "module_manager.h" +#include "bitstream_manager.h" +#include "circuit_library.h" + +void print_verilog_top_testbench(const ModuleManager& module_manager, + const BitstreamManager& bitstream_manager, + const std::vector& fabric_bitstream, + const e_sram_orgz& sram_orgz_type, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports, + const std::vector& L_logical_blocks, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, + const std::string& circuit_name, + const std::string& verilog_fname, + const std::string& verilog_dir, + const std::string& reference_benchmark_file, + const t_spice_params& simulation_parameters); void dump_verilog_top_testbench_global_ports(FILE* fp, t_llist* head, enum e_dump_verilog_port_type dump_port_type); @@ -15,7 +39,7 @@ void dump_verilog_top_testbench_stimuli(t_sram_orgz_info* cur_sram_orgz_info, void dump_verilog_top_testbench(t_sram_orgz_info* cur_sram_orgz_info, char* circuit_name, - char* top_netlist_name, + const char* top_netlist_name, char* verilog_dir_path, t_spice verilog); @@ -23,3 +47,5 @@ void dump_verilog_input_blif_testbench(char* circuit_name, char* top_netlist_name, char* verilog_dir_path, t_spice verilog); + +#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 69f774592..d2593138b 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 @@ -6,6 +6,8 @@ #include #include #include +#include + #include "vtr_assert.h" /* Device-level header files */ @@ -1210,3 +1212,131 @@ void print_verilog_formal_verification_mux_sram_ports_wiring(std::fstream& fp, print_verilog_wire_connection(fp, mux_sram_output, formal_verification_port, false); } +/******************************************************************** + * Print stimuli for a pulse generation + * + * |<--- pulse width --->| + * +------ flip_value + * | + * initial_value ----------------------+ + * + *******************************************************************/ +void print_verilog_pulse_stimuli(std::fstream& fp, + const BasicPort& port, + const size_t& initial_value, + const float& pulse_width, + const size_t& flip_value) { + /* Validate the file stream */ + check_file_handler(fp); + + /* Config_done signal: indicate when configuration is finished */ + fp << "initial" << std::endl; + fp << "\tbegin" << std::endl; + fp << "\t"; + std::vector initial_values(port.get_width(), initial_value); + print_verilog_wire_constant_values(fp, port, initial_values); + + /* if flip_value is the same as initial value, we do not need to flip the signal ! */ + if (flip_value != initial_value) { + fp << "\t" << "#" << std::setprecision(2) << pulse_width; + std::vector port_flip_values(port.get_width(), flip_value); + print_verilog_wire_constant_values(fp, port, port_flip_values); + } + + fp << "\tend" << std::endl; + + /* Print an empty line as splitter */ + fp << std::endl; +} + +/******************************************************************** + * Print stimuli for a pulse generation + * This function supports multiple signal switching under different pulse width + * + * |<-- wait condition -->| + * |<--- pulse width --->| + * +------ flip_values + * | + * initial_value ------- ... --------------------------------+ + * + *******************************************************************/ +void print_verilog_pulse_stimuli(std::fstream& fp, + const BasicPort& port, + const size_t& initial_value, + const std::vector& pulse_widths, + const std::vector& flip_values, + const std::string& wait_condition) { + /* Validate the file stream */ + check_file_handler(fp); + + /* Config_done signal: indicate when configuration is finished */ + fp << "initial" << std::endl; + fp << "\tbegin" << std::endl; + fp << "\t"; + std::vector initial_values(port.get_width(), initial_value); + print_verilog_wire_constant_values(fp, port, initial_values); + + /* Set a wait condition if specified */ + if (false == wait_condition.empty()) { + fp << "\twait(" << wait_condition << ")" << std::endl; + } + + /* Number of flip conditions and values should match */ + VTR_ASSERT(flip_values.size() == pulse_widths.size()); + for (size_t ipulse = 0; ipulse < pulse_widths.size(); ++ipulse) { + fp << "\t" << "#" << std::setprecision(2) << pulse_widths[ipulse]; + std::vector port_flip_value(port.get_width(), flip_values[ipulse]); + print_verilog_wire_constant_values(fp, port, port_flip_value); + } + + fp << "\tend" << std::endl; + + /* Print an empty line as splitter */ + fp << std::endl; +} + +/******************************************************************** + * Print stimuli for a clock signal + * This function can support if the clock signal should wait for a period + * of time and then start + * pulse width + * |<----->| + * +-------+ +-------+ + * | | | | + * initial_value --- ... ---+ +-------+ +------ ... + * |<--wait_condition-->| + * + *******************************************************************/ +void print_verilog_clock_stimuli(std::fstream& fp, + const BasicPort& port, + const size_t& initial_value, + const float& pulse_width, + const std::string& wait_condition) { + /* Validate the file stream */ + check_file_handler(fp); + + /* Config_done signal: indicate when configuration is finished */ + fp << "initial" << std::endl; + fp << "\tbegin" << std::endl; + fp << "\t"; + std::vector initial_values(port.get_width(), initial_value); + print_verilog_wire_constant_values(fp, port, initial_values); + fp << "\tend" << std::endl; + fp << "always"; + + /* Set a wait condition if specified */ + if (true == wait_condition.empty()) { + fp << std::endl; + } else { + fp << " wait(" << wait_condition << ")" << std::endl; + } + + fp << "\tbegin" << std::endl; + fp << "\t\t" << "#" << std::setprecision(2) << pulse_width; + print_verilog_wire_connection(fp, port, port, true); + fp << "\tend" << std::endl; + + /* Print an empty line as splitter */ + fp << std::endl; +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h index d09e950de..a1d57615a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h @@ -6,6 +6,8 @@ #ifndef VERILOG_WRITER_UTILS_H #define VERILOG_WRITER_UTILS_H +#include +#include #include #include "verilog_global.h" #include "device_port.h" @@ -143,4 +145,23 @@ void print_verilog_formal_verification_mux_sram_ports_wiring(std::fstream& fp, const size_t& num_conf_bits, const BasicPort& fm_config_bus); +void print_verilog_pulse_stimuli(std::fstream& fp, + const BasicPort& port, + const size_t& initial_value, + const float& pulse_width, + const size_t& flip_value); + +void print_verilog_pulse_stimuli(std::fstream& fp, + const BasicPort& port, + const size_t& initial_value, + const std::vector& pulse_widths, + const std::vector& flip_values, + const std::string& wait_condition); + +void print_verilog_clock_stimuli(std::fstream& fp, + const BasicPort& port, + const size_t& initial_value, + const float& pulse_width, + const std::string& wait_condition); + #endif From 1fb29df1e2e1c8cc4b00146ea7cbed7b4f3b5ec8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 3 Nov 2019 17:58:18 -0700 Subject: [PATCH 19/68] cleaning verilog file lines --- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 73270144c..1037106b0 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -399,16 +399,6 @@ void vpr_fpga_verilog(ModuleManager& module_manager, /* TODO: this is an old function, to be shadowed */ dump_verilog_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, top_testbench_file_path.c_str(), src_dir_path, *(Arch.spice)); - /* TODO: new function: to be tested */ - print_verilog_top_testbench(module_manager, bitstream_manager, fabric_bitstream, - sram_verilog_orgz_info->type, - Arch.spice->circuit_lib, global_ports, - L_logical_blocks, device_size, L_grids, L_blocks, - std::string(chomped_circuit_name), - std::string(top_testbench_file_path + std::string(".bak")), - std::string(src_dir_path), - std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file), - Arch.spice->spice_params); } if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_formal_verification_top_netlist) { @@ -461,6 +451,16 @@ void vpr_fpga_verilog(ModuleManager& module_manager, dump_verilog_autocheck_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, autocheck_top_testbench_file_path.c_str(), src_dir_path, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, *(Arch.spice)); + /* TODO: new function: to be tested */ + print_verilog_top_testbench(module_manager, bitstream_manager, fabric_bitstream, + sram_verilog_orgz_info->type, + Arch.spice->circuit_lib, global_ports, + L_logical_blocks, device_size, L_grids, L_blocks, + std::string(chomped_circuit_name), + std::string(autocheck_top_testbench_file_path + std::string(".bak")), + std::string(src_dir_path), + std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file), + Arch.spice->spice_params); } /* Output Modelsim Autodeck scripts */ From 3e9968d2f08c9c52492e39cde660ce3116faef95 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 3 Nov 2019 18:59:54 -0700 Subject: [PATCH 20/68] keep refactoring top-level testbench with auto-check features --- .../verilog_formal_random_top_testbench.cpp | 168 +--- .../verilog/verilog_testbench_utils.cpp | 158 +++- .../verilog/verilog_testbench_utils.h | 22 + .../verilog/verilog_top_testbench.cpp | 829 ++++++++++++++++++ 4 files changed, 1025 insertions(+), 152 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp index 78f14b07b..362992bc2 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp @@ -41,22 +41,6 @@ constexpr char* ERROR_COUNTER = "nb_error"; constexpr char* FORMAL_TB_SIM_START_PORT_NAME = "sim_start"; constexpr int MAGIC_NUMBER_FOR_SIMULATION_TIME = 200; -/******************************************************************** - * Generate the clock port name to be used in this testbench - * - * Restrictions: - * Assume this is a single clock benchmark - *******************************************************************/ -static -BasicPort generate_verilog_top_clock_port(const std::vector& clock_port_names) { - if (0 == clock_port_names.size()) { - return BasicPort(std::string(DEFAULT_CLOCK_NAME), 1); - } - - VTR_ASSERT(1 == clock_port_names.size()); - return BasicPort(clock_port_names[0], 1); -} - /******************************************************************** * Print the module ports for the Verilog testbench * using random vectors @@ -97,7 +81,7 @@ void print_verilog_top_random_testbench_ports(std::fstream& fp, * The clock is used for counting and synchronizing input stimulus */ if (0 == clock_port_names.size()) { - BasicPort clock_port = generate_verilog_top_clock_port(clock_port_names); + BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME)); print_verilog_comment(fp, std::string("----- Default clock port is added here since benchmark does not contain one -------")); fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, clock_port) << ";" << std::endl; } @@ -213,137 +197,6 @@ void print_verilog_top_random_testbench_benchmark_instance(std::fstream& fp, fp << std::endl; } -/******************************************************************** - * Print Verilog codes to set up a timeout for the simulation - * and dump the waveform to VCD files - * - * Note that: these codes are tuned for Icarus simulator!!! - *******************************************************************/ -static -void print_verilog_timeout_and_vcd(std::fstream& fp, - const std::string& circuit_name, - const int& simulation_time) { - /* Validate the file stream */ - check_file_handler(fp); - - /* The following verilog codes are tuned for Icarus */ - print_verilog_preprocessing_flag(fp, std::string(icarus_simulator_flag)); - - print_verilog_comment(fp, std::string("----- Begin Icarus requirement -------")); - - fp << "\tinitial begin" << std::endl; - fp << "\t\t$dumpfile(\"" << circuit_name << "_formal.vcd\");" << std::endl; - fp << "\t\t$dumpvars(1, " << circuit_name << FORMAL_RANDOM_TOP_TESTBENCH_POSTFIX << ");" << std::endl; - fp << "\tend" << std::endl; - - /* Condition ends for the Icarus requirement */ - print_verilog_endif(fp); - - print_verilog_comment(fp, std::string("----- END Icarus requirement -------")); - - /* Add an empty line as splitter */ - fp << std::endl; - - BasicPort sim_start_port(std::string(FORMAL_TB_SIM_START_PORT_NAME), 1); - - fp << "initial begin" << std::endl; - fp << "\t" << generate_verilog_port(VERILOG_PORT_CONKT, sim_start_port) << " <= 1'b1;" << std::endl; - fp << "\t$timeformat(-9, 2, \"ns\", 20);" << std::endl; - fp << "\t$display(\"Simulation start\");" << std::endl; - print_verilog_comment(fp, std::string("----- Can be changed by the user for his/her need -------")); - fp << "\t#" << simulation_time << std::endl; - fp << "\tif(" << ERROR_COUNTER << " == 0) begin" << std::endl; - fp << "\t\t$display(\"Simulation Succeed\");" << std::endl; - fp << "\tend else begin" << std::endl; - fp << "\t\t$display(\"Simulation Failed with " << std::string("%d") << " error(s)\", " << ERROR_COUNTER << ");" << std::endl; - fp << "\tend" << std::endl; - fp << "\t$finish;" << std::endl; - fp << "end" << std::endl; - - /* Add an empty line as splitter */ - fp << std::endl; -} - -/******************************************************************** - * Print Verilog codes to check the equivalence of output vectors - * - * Restriction: this function only supports single clock benchmarks! - *******************************************************************/ -static -void print_verilog_top_random_testbench_check(std::fstream& fp, - const std::vector& L_logical_blocks, - const std::vector& clock_port_names) { - - /* Validate the file stream */ - check_file_handler(fp); - - /* Add output autocheck conditionally: only when a preprocessing flag is enable */ - print_verilog_preprocessing_flag(fp, std::string(autochecked_simulation_flag)); - - print_verilog_comment(fp, std::string("----- Begin checking output vectors -------")); - - BasicPort clock_port = generate_verilog_top_clock_port(clock_port_names); - - print_verilog_comment(fp, std::string("----- Skip the first falling edge of clock, it is for initialization -------")); - - BasicPort sim_start_port(std::string(FORMAL_TB_SIM_START_PORT_NAME), 1); - - fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, sim_start_port) << ";" << std::endl; - fp << std::endl; - - fp << "\talways@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << ") begin" << std::endl; - fp << "\t\tif (1'b1 == " << generate_verilog_port(VERILOG_PORT_CONKT, sim_start_port) << ") begin" << std::endl; - fp << "\t\t"; - print_verilog_register_connection(fp, sim_start_port, sim_start_port, true); - fp << "\t\tend else begin" << std::endl; - - for (const t_logical_block& lb : L_logical_blocks) { - /* Bypass non-I/O logical blocks ! */ - if ( (VPACK_INPAD != lb.type) && (VPACK_OUTPAD != lb.type) ) { - continue; - } - - if (VPACK_OUTPAD == lb.type){ - fp << "\t\t\tif(!(" << std::string(lb.name) << std::string(FPGA_PORT_POSTFIX); - fp << " === " << std::string(lb.name) << std::string(BENCHMARK_PORT_POSTFIX); - fp << ") && !(" << std::string(lb.name) << std::string(BENCHMARK_PORT_POSTFIX); - fp << " === 1'bx)) begin" << std::endl; - fp << "\t\t\t\t" << std::string(lb.name) << std::string(CHECKFLAG_PORT_POSTFIX) << " <= 1'b1;" << std::endl; - fp << "\t\t\tend else begin" << std::endl; - fp << "\t\t\t\t" << std::string(lb.name) << std::string(CHECKFLAG_PORT_POSTFIX) << "<= 1'b0;" << std::endl; - fp << "\t\t\tend" << std::endl; - } - } - fp << "\t\tend" << std::endl; - fp << "\tend" << std::endl; - - /* Add an empty line as splitter */ - fp << std::endl; - - for (const t_logical_block& lb : L_logical_blocks) { - /* Bypass non-I/O logical blocks ! */ - if (VPACK_OUTPAD != lb.type) { - continue; - } - - fp << "\talways@(posedge " << std::string(lb.name) << std::string(CHECKFLAG_PORT_POSTFIX) << ") begin" << std::endl; - fp << "\t\tif(" << std::string(lb.name) << std::string(CHECKFLAG_PORT_POSTFIX) << ") begin" << std::endl; - fp << "\t\t\t" << ERROR_COUNTER << " = " << ERROR_COUNTER << " + 1;" << std::endl; - fp << "\t\t\t$display(\"Mismatch on " << std::string(lb.name) << std::string(FPGA_PORT_POSTFIX) << " at time = " << std::string("%t") << "\", $realtime);" << std::endl; - fp << "\t\tend" << std::endl; - fp << "\tend" << std::endl; - - /* Add an empty line as splitter */ - fp << std::endl; - } - - /* Condition ends */ - print_verilog_endif(fp); - - /* Add an empty line as splitter */ - fp << std::endl; -} - /******************************************************************** * Instanciate the FPGA fabric module *******************************************************************/ @@ -385,7 +238,7 @@ void print_verilog_top_random_stimuli(std::fstream& fp, fp << "\tinitial begin" << std::endl; /* Create clock stimuli */ - BasicPort clock_port = generate_verilog_top_clock_port(clock_port_names); + BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME)); fp << "\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << " <= 1'b0;" << std::endl; fp << "\t\twhile(1) begin" << std::endl; fp << "\t\t\t#" << std::setprecision(2) << ((0.5/simulation_parameters.stimulate_params.op_clock_freq)/verilog_sim_timescale) << std::endl; @@ -540,7 +393,14 @@ void print_verilog_random_top_testbench(const std::string& circuit_name, /* Add stimuli for reset, set, clock and iopad signals */ print_verilog_top_random_stimuli(fp, simulation_parameters, L_logical_blocks, clock_port_names); - print_verilog_top_random_testbench_check(fp, L_logical_blocks, clock_port_names); + print_verilog_testbench_check(fp, + std::string(autochecked_simulation_flag), + std::string(FORMAL_TB_SIM_START_PORT_NAME), + std::string(BENCHMARK_PORT_POSTFIX), + std::string(FPGA_PORT_POSTFIX), + std::string(CHECKFLAG_PORT_POSTFIX), + std::string(ERROR_COUNTER), + L_logical_blocks, clock_port_names, std::string(DEFAULT_CLOCK_NAME)); int simulation_time = find_operating_phase_simulation_time(MAGIC_NUMBER_FOR_SIMULATION_TIME, simulation_parameters.meas_params.sim_num_clock_cycle, @@ -548,7 +408,13 @@ void print_verilog_random_top_testbench(const std::string& circuit_name, verilog_sim_timescale); /* Add Icarus requirement */ - print_verilog_timeout_and_vcd(fp, circuit_name, simulation_time); + print_verilog_timeout_and_vcd(fp, + std::string(icarus_simulator_flag), + std::string(circuit_name + std::string(FORMAL_RANDOM_TOP_TESTBENCH_POSTFIX)), + std::string(circuit_name + std::string("_formal.vcd")), + std::string(FORMAL_TB_SIM_START_PORT_NAME), + std::string(ERROR_COUNTER), + simulation_time); /* Testbench ends*/ print_verilog_module_end(fp, std::string(circuit_name) + std::string(FORMAL_RANDOM_TOP_TESTBENCH_POSTFIX)); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp index c1784ab26..d0b5e6b78 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp @@ -2,7 +2,7 @@ * This file includes most utilized functions that are used to create * Verilog testbenches * - * Note: please do NOT use global variables in this file + * Note: please try to avoid using global variables in this file * so that we can make it free to use anywhere *******************************************************************/ #include "vtr_assert.h" @@ -176,3 +176,159 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, /* Add an empty line as a splitter */ fp << std::endl; } + +/******************************************************************** + * Print Verilog codes to set up a timeout for the simulation + * and dump the waveform to VCD files + * + * Note that: these codes are tuned for Icarus simulator!!! + *******************************************************************/ +void print_verilog_timeout_and_vcd(std::fstream& fp, + const std::string& icarus_preprocessing_flag, + const std::string& module_name, + const std::string& vcd_fname, + const std::string& simulation_start_counter_name, + const std::string& error_counter_name, + const int& simulation_time) { + /* Validate the file stream */ + check_file_handler(fp); + + /* The following verilog codes are tuned for Icarus */ + print_verilog_preprocessing_flag(fp, icarus_preprocessing_flag); + + print_verilog_comment(fp, std::string("----- Begin Icarus requirement -------")); + + fp << "\tinitial begin" << std::endl; + fp << "\t\t$dumpfile(\"" << vcd_fname << "\");" << std::endl; + fp << "\t\t$dumpvars(1, " << module_name << ");" << std::endl; + fp << "\tend" << std::endl; + + /* Condition ends for the Icarus requirement */ + print_verilog_endif(fp); + + print_verilog_comment(fp, std::string("----- END Icarus requirement -------")); + + /* Add an empty line as splitter */ + fp << std::endl; + + BasicPort sim_start_port(simulation_start_counter_name, 1); + + fp << "initial begin" << std::endl; + fp << "\t" << generate_verilog_port(VERILOG_PORT_CONKT, sim_start_port) << " <= 1'b1;" << std::endl; + fp << "\t$timeformat(-9, 2, \"ns\", 20);" << std::endl; + fp << "\t$display(\"Simulation start\");" << std::endl; + print_verilog_comment(fp, std::string("----- Can be changed by the user for his/her need -------")); + fp << "\t#" << simulation_time << std::endl; + fp << "\tif(" << error_counter_name << " == 0) begin" << std::endl; + fp << "\t\t$display(\"Simulation Succeed\");" << std::endl; + fp << "\tend else begin" << std::endl; + fp << "\t\t$display(\"Simulation Failed with " << std::string("%d") << " error(s)\", " << error_counter_name << ");" << std::endl; + fp << "\tend" << std::endl; + fp << "\t$finish;" << std::endl; + fp << "end" << std::endl; + + /* Add an empty line as splitter */ + fp << std::endl; +} + +/******************************************************************** + * Generate the clock port name to be used in this testbench + * + * Restrictions: + * Assume this is a single clock benchmark + *******************************************************************/ +BasicPort generate_verilog_testbench_clock_port(const std::vector& clock_port_names, + const std::string& default_clock_name) { + if (0 == clock_port_names.size()) { + return BasicPort(default_clock_name, 1); + } + + VTR_ASSERT(1 == clock_port_names.size()); + return BasicPort(clock_port_names[0], 1); +} + +/******************************************************************** + * Print Verilog codes to check the equivalence of output vectors + * + * Restriction: this function only supports single clock benchmarks! + *******************************************************************/ +void print_verilog_testbench_check(std::fstream& fp, + const std::string& autochecked_preprocessing_flag, + const std::string& simulation_start_counter_name, + const std::string& benchmark_port_postfix, + const std::string& fpga_port_postfix, + const std::string& check_flag_port_postfix, + const std::string& error_counter_name, + const std::vector& L_logical_blocks, + const std::vector& clock_port_names, + const std::string& default_clock_name) { + + /* Validate the file stream */ + check_file_handler(fp); + + /* Add output autocheck conditionally: only when a preprocessing flag is enable */ + print_verilog_preprocessing_flag(fp, autochecked_preprocessing_flag); + + print_verilog_comment(fp, std::string("----- Begin checking output vectors -------")); + + BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, default_clock_name); + + print_verilog_comment(fp, std::string("----- Skip the first falling edge of clock, it is for initialization -------")); + + BasicPort sim_start_port(simulation_start_counter_name, 1); + + fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, sim_start_port) << ";" << std::endl; + fp << std::endl; + + fp << "\talways@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << ") begin" << std::endl; + fp << "\t\tif (1'b1 == " << generate_verilog_port(VERILOG_PORT_CONKT, sim_start_port) << ") begin" << std::endl; + fp << "\t\t"; + print_verilog_register_connection(fp, sim_start_port, sim_start_port, true); + fp << "\t\tend else begin" << std::endl; + + for (const t_logical_block& lb : L_logical_blocks) { + /* Bypass non-I/O logical blocks ! */ + if ( (VPACK_INPAD != lb.type) && (VPACK_OUTPAD != lb.type) ) { + continue; + } + + if (VPACK_OUTPAD == lb.type){ + fp << "\t\t\tif(!(" << std::string(lb.name) << fpga_port_postfix; + fp << " === " << std::string(lb.name) << benchmark_port_postfix; + fp << ") && !(" << std::string(lb.name) << benchmark_port_postfix; + fp << " === 1'bx)) begin" << std::endl; + fp << "\t\t\t\t" << std::string(lb.name) << check_flag_port_postfix << " <= 1'b1;" << std::endl; + fp << "\t\t\tend else begin" << std::endl; + fp << "\t\t\t\t" << std::string(lb.name) << check_flag_port_postfix << "<= 1'b0;" << std::endl; + fp << "\t\t\tend" << std::endl; + } + } + fp << "\t\tend" << std::endl; + fp << "\tend" << std::endl; + + /* Add an empty line as splitter */ + fp << std::endl; + + for (const t_logical_block& lb : L_logical_blocks) { + /* Bypass non-I/O logical blocks ! */ + if (VPACK_OUTPAD != lb.type) { + continue; + } + + fp << "\talways@(posedge " << std::string(lb.name) << check_flag_port_postfix << ") begin" << std::endl; + fp << "\t\tif(" << std::string(lb.name) << check_flag_port_postfix << ") begin" << std::endl; + fp << "\t\t\t" << error_counter_name << " = " << error_counter_name << " + 1;" << std::endl; + fp << "\t\t\t$display(\"Mismatch on " << std::string(lb.name) << fpga_port_postfix << " at time = " << std::string("%t") << "\", $realtime);" << std::endl; + fp << "\t\tend" << std::endl; + fp << "\tend" << std::endl; + + /* Add an empty line as splitter */ + fp << std::endl; + } + + /* Condition ends */ + print_verilog_endif(fp); + + /* Add an empty line as splitter */ + fp << std::endl; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h index ffa7411eb..b344bee5f 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h @@ -32,4 +32,26 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, const std::string& io_port_name_postfix, const size_t& unused_io_value); +void print_verilog_timeout_and_vcd(std::fstream& fp, + const std::string& icarus_preprocessing_flag, + const std::string& module_name, + const std::string& vcd_fname, + const std::string& simulation_start_counter_name, + const std::string& error_counter_name, + const int& simulation_time); + +BasicPort generate_verilog_testbench_clock_port(const std::vector& clock_port_names, + const std::string& default_clock_name); + +void print_verilog_testbench_check(std::fstream& fp, + const std::string& autochecked_preprocessing_flag, + const std::string& simulation_start_counter_name, + const std::string& benchmark_port_postfix, + const std::string& fpga_port_postfix, + const std::string& check_flag_port_postfix, + const std::string& error_counter_name, + const std::vector& L_logical_blocks, + const std::vector& clock_port_names, + const std::string& default_clock_name); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp new file mode 100644 index 000000000..febbf37a0 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp @@ -0,0 +1,829 @@ +/******************************************************************** + * This file includes functions that are used to create + * an auto-check top-level testbench for a FPGA fabric + *******************************************************************/ +#include +#include +#include +#include + +#include "vtr_assert.h" +#include "device_port.h" +#include "util.h" + +#include "bitstream_manager_utils.h" + +#include "fpga_x2p_naming.h" +#include "fpga_x2p_utils.h" +#include "simulation_utils.h" +#include "fpga_x2p_benchmark_utils.h" + +#include "verilog_global.h" +#include "verilog_writer_utils.h" +#include "verilog_testbench_utils.h" +#include "verilog_top_testbench.h" + +/******************************************************************** + * Local variables used only in this file + *******************************************************************/ +constexpr char* TOP_TESTBENCH_REFERENCE_INSTANCE_NAME = "REF_DUT"; +constexpr char* TOP_TESTBENCH_FPGA_INSTANCE_NAME = "FPGA_DUT"; +constexpr char* TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX = "_benchmark"; +constexpr char* TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX = "_verification"; + +constexpr char* TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX = "_flag"; + +constexpr char* TOP_TESTBENCH_CONFIG_CHAIN_HEAD_PORT_NAME = "cc_in"; +constexpr char* TOP_TESTBENCH_CONFIG_CHAIN_TAIL_PORT_NAME = "cc_out"; +constexpr char* TOP_TESTBENCH_CC_PROG_TASK_NAME = "prog_cycle_task"; + +constexpr char* TOP_TESTBENCH_SIM_START_PORT_NAME = "sim_start"; + +constexpr int TOP_TESTBENCH_MAGIC_NUMBER_FOR_SIMULATION_TIME = 200; +constexpr char* TOP_TESTBENCH_ERROR_COUNTER = "nb_error"; + +/******************************************************************** + * Print local wires for configuration chain protocols + *******************************************************************/ +static +void print_verilog_top_testbench_config_chain_port(std::fstream& fp) { + /* Validate the file stream */ + check_file_handler(fp); + + /* Print the head of configuraion-chains here */ + print_verilog_comment(fp, std::string("---- Configuration-chain head -----")); + BasicPort config_chain_head_port(std::string(TOP_TESTBENCH_CONFIG_CHAIN_HEAD_PORT_NAME), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, config_chain_head_port) << ";" << std::endl; + + /* Print the tail of configuration-chains here */ + print_verilog_comment(fp, std::string("---- Configuration-chain tail -----")); + BasicPort config_chain_tail_port(std::string(TOP_TESTBENCH_CONFIG_CHAIN_TAIL_PORT_NAME), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, config_chain_tail_port) << ";" << std::endl; +} + +/******************************************************************** + * Print local wires for different types of configuration protocols + *******************************************************************/ +static +void print_verilog_top_testbench_config_protocol_port(std::fstream& fp, + const e_sram_orgz& sram_orgz_type) { + switch(sram_orgz_type) { + case SPICE_SRAM_STANDALONE: + /* TODO */ + break; + case SPICE_SRAM_SCAN_CHAIN: + print_verilog_top_testbench_config_chain_port(fp); + break; + case SPICE_SRAM_MEMORY_BANK: + /* TODO */ + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid type of SRAM organization!\n", + __FILE__, __LINE__); + exit(1); + } +} + +/******************************************************************** + * Wire the global ports of FPGA fabric to local wires + *******************************************************************/ +static +void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports) { + /* Validate the file stream */ + check_file_handler(fp); + + print_verilog_comment(fp, std::string("----- Begin connecting global ports of FPGA fabric to stimuli -----")); + + /* Connect global clock ports to operating or programming clock signal */ + for (const CircuitPortId& model_global_port : global_ports) { + if (SPICE_MODEL_PORT_CLOCK != circuit_lib.port_type(model_global_port)) { + continue; + } + /* Reach here, it means we have a global clock to deal with: + * 1. if the port is identified as a programming clock, + * connect it to the local wire of programming clock + * 2. if the port is identified as an operating clock + * connect it to the local wire of operating clock + */ + /* Find the module port */ + ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_lib_name(model_global_port)); + VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); + + BasicPort stimuli_clock_port; + if (true == circuit_lib.port_is_prog(model_global_port)) { + stimuli_clock_port.set_name(std::string(top_tb_prog_clock_port_name)); + stimuli_clock_port.set_width(1); + } else { + VTR_ASSERT_SAFE(false == circuit_lib.port_is_prog(model_global_port)); + stimuli_clock_port.set_name(std::string(top_tb_op_clock_port_name)); + stimuli_clock_port.set_width(1); + } + /* Wire the port to the input stimuli: + * The wiring will be inverted if the default value of the global port is 1 + * Otherwise, the wiring will not be inverted! + */ + print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port), + stimuli_clock_port, + 1 == circuit_lib.port_default_value(model_global_port)); + } + + /* Connect global configuration done ports to configuration done signal */ + for (const CircuitPortId& model_global_port : global_ports) { + /* Bypass clock signals, they have been processed */ + if (SPICE_MODEL_PORT_CLOCK == circuit_lib.port_type(model_global_port)) { + continue; + } + if (false == circuit_lib.port_is_config_enable(model_global_port)) { + continue; + } + /* Reach here, it means we have a configuration done port to deal with */ + /* Find the module port */ + ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_lib_name(model_global_port)); + VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); + + BasicPort stimuli_config_done_port(std::string(top_tb_config_done_port_name), 1); + /* Wire the port to the input stimuli: + * The wiring will be inverted if the default value of the global port is 1 + * Otherwise, the wiring will not be inverted! + */ + print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port), + stimuli_config_done_port, + 1 == circuit_lib.port_default_value(model_global_port)); + } + + /* Connect global reset ports to operating or programming reset signal */ + for (const CircuitPortId& model_global_port : global_ports) { + /* Bypass clock signals, they have been processed */ + if (SPICE_MODEL_PORT_CLOCK == circuit_lib.port_type(model_global_port)) { + continue; + } + /* Bypass config_done signals, they have been processed */ + if (true == circuit_lib.port_is_config_enable(model_global_port)) { + continue; + } + + if (false == circuit_lib.port_is_reset(model_global_port)) { + continue; + } + /* Reach here, it means we have a reset port to deal with */ + /* Find the module port */ + ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_lib_name(model_global_port)); + VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); + + BasicPort stimuli_reset_port; + if (true == circuit_lib.port_is_prog(model_global_port)) { + stimuli_reset_port.set_name(std::string(top_tb_prog_reset_port_name)); + stimuli_reset_port.set_width(1); + } else { + VTR_ASSERT_SAFE(false == circuit_lib.port_is_prog(model_global_port)); + stimuli_reset_port.set_name(std::string(top_tb_reset_port_name)); + stimuli_reset_port.set_width(1); + } + /* Wire the port to the input stimuli: + * The wiring will be inverted if the default value of the global port is 1 + * Otherwise, the wiring will not be inverted! + */ + print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port), + stimuli_reset_port, + 1 == circuit_lib.port_default_value(model_global_port)); + } + + /* Connect global set ports to operating or programming set signal */ + for (const CircuitPortId& model_global_port : global_ports) { + /* Bypass clock signals, they have been processed */ + if (SPICE_MODEL_PORT_CLOCK == circuit_lib.port_type(model_global_port)) { + continue; + } + /* Bypass config_done signals, they have been processed */ + if (true == circuit_lib.port_is_config_enable(model_global_port)) { + continue; + } + + /* Bypass reset signals, they have been processed */ + if (true == circuit_lib.port_is_reset(model_global_port)) { + continue; + } + + if (false == circuit_lib.port_is_set(model_global_port)) { + continue; + } + /* Reach here, it means we have a set port to deal with */ + /* Find the module port */ + ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_lib_name(model_global_port)); + VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); + + BasicPort stimuli_set_port; + if (true == circuit_lib.port_is_prog(model_global_port)) { + stimuli_set_port.set_name(std::string(top_tb_prog_set_port_name)); + stimuli_set_port.set_width(1); + } else { + VTR_ASSERT_SAFE(false == circuit_lib.port_is_prog(model_global_port)); + stimuli_set_port.set_name(std::string(top_tb_set_port_name)); + stimuli_set_port.set_width(1); + } + /* Wire the port to the input stimuli: + * The wiring will be inverted if the default value of the global port is 1 + * Otherwise, the wiring will not be inverted! + */ + print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port), + stimuli_set_port, + 1 == circuit_lib.port_default_value(model_global_port)); + } + + /* For the rest of global ports, wire them to constant signals */ + for (const CircuitPortId& model_global_port : global_ports) { + /* Bypass clock signals, they have been processed */ + if (SPICE_MODEL_PORT_CLOCK == circuit_lib.port_type(model_global_port)) { + continue; + } + /* Bypass config_done signals, they have been processed */ + if (true == circuit_lib.port_is_config_enable(model_global_port)) { + continue; + } + + /* Bypass reset signals, they have been processed */ + if (true == circuit_lib.port_is_reset(model_global_port)) { + continue; + } + + /* Bypass set signals, they have been processed */ + if (true == circuit_lib.port_is_set(model_global_port)) { + continue; + } + + /* Reach here, it means we have a port to deal with */ + /* Find the module port and wire it to constant values */ + ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_lib_name(model_global_port)); + VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); + + BasicPort module_port = module_manager.module_port(top_module, module_global_port); + std::vector default_values(module_port.get_width(), circuit_lib.port_default_value(model_global_port)); + print_verilog_wire_constant_values(fp, module_port, default_values); + } + + print_verilog_comment(fp, std::string("----- End connecting global ports of FPGA fabric to stimuli -----")); +} + +/******************************************************************** + * This function prints the top testbench module declaration + * and internal wires/port declaration + * Ports can be classified in two categories: + * 1. General-purpose ports, which are datapath I/Os, clock signals + * for the FPGA fabric and input benchmark + * 2. Fabric-featured ports, which are required by configuration + * protocols. + * Due the difference in configuration protocols, the internal + * wires and ports will be different: + * (a) configuration-chain: we will have two ports, + * a head and a tail for the configuration chain, + * in addition to the regular ports. + * (b) memory-decoders: we will have a few ports to drive + * address lines for decoders and a bit input port to feed + * configuration bits + *******************************************************************/ +static +void print_verilog_top_testbench_ports(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const e_sram_orgz& sram_orgz_type, + const std::string& circuit_name){ + /* Validate the file stream */ + check_file_handler(fp); + + /* Print module definition */ + fp << "module " << circuit_name << std::string(modelsim_autocheck_testbench_module_postfix); + fp << " (" << std::endl; + + /* Print regular local wires: + * 1. global ports, i.e., reset, set and clock signals + * 2. datapath I/O signals + */ + /* Global ports of top-level module */ + print_verilog_comment(fp, std::string("----- Local wires for global ports of FPGA fabric -----")); + for (const BasicPort& module_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GLOBAL_PORT)) { + fp << generate_verilog_port(VERILOG_PORT_REG, module_port) << ";" << std::endl; + } + /* Add an empty line as a splitter */ + fp << std::endl; + + /* Datapath I/Os of top-level module */ + print_verilog_comment(fp, std::string("----- Local wires for I/Os of FPGA fabric -----")); + for (const BasicPort& module_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)) { + fp << generate_verilog_port(VERILOG_PORT_REG, module_port) << ";" << std::endl; + } + /* Add an empty line as a splitter */ + fp << std::endl; + + /* Add local wires/registers that drive stimulus + * We create these general purpose ports here, + * and then wire them to the ports of FPGA fabric depending on their usage + */ + /* Configuration done port */ + BasicPort config_done_port(std::string(top_tb_config_done_port_name), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, config_done_port) << ";" << std::endl; + + /* Programming clock */ + BasicPort prog_clock_port(std::string(top_tb_prog_clock_port_name), 1); + fp << generate_verilog_port(VERILOG_PORT_WIRE, prog_clock_port) << ";" << std::endl; + BasicPort prog_clock_register_port(std::string(std::string(top_tb_prog_clock_port_name) + std::string(top_tb_clock_reg_postfix)), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, prog_clock_register_port) << ";" << std::endl; + + /* Operating clock */ + BasicPort op_clock_port(std::string(top_tb_op_clock_port_name), 1); + fp << generate_verilog_port(VERILOG_PORT_WIRE, op_clock_port) << ";" << std::endl; + BasicPort op_clock_register_port(std::string(std::string(top_tb_op_clock_port_name) + std::string(top_tb_clock_reg_postfix)), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, op_clock_register_port) << ";" << std::endl; + + /* Programming set and reset */ + BasicPort prog_reset_port(std::string(top_tb_prog_reset_port_name), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, prog_reset_port) << ";" << std::endl; + BasicPort prog_set_port(std::string(top_tb_prog_set_port_name), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, prog_set_port) << ";" << std::endl; + + /* Global set and reset */ + BasicPort reset_port(std::string(top_tb_reset_port_name), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, reset_port) << ";" << std::endl; + BasicPort set_port(std::string(top_tb_set_port_name), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, set_port) << ";" << std::endl; + + /* Configuration ports depend on the organization of SRAMs */ + print_verilog_top_testbench_config_protocol_port(fp, sram_orgz_type); + + /* Instantiate an integer to count the number of error and + * determine if the simulation succeed or failed + */ + print_verilog_comment(fp, std::string("----- Error counter -----")); + fp << "\tinteger " << TOP_TESTBENCH_ERROR_COUNTER << "= 0;" << std::endl; +} + +/******************************************************************** + * Instanciate the input benchmark module + *******************************************************************/ +static +void print_verilog_top_testbench_benchmark_instance(std::fstream& fp, + const std::string& reference_verilog_top_name, + const std::vector& L_logical_blocks) { + /* Validate the file stream */ + check_file_handler(fp); + + /* Benchmark is instanciated conditionally: only when a preprocessing flag is enable */ + print_verilog_preprocessing_flag(fp, std::string(autochecked_simulation_flag)); + + print_verilog_comment(fp, std::string("----- Reference Benchmark Instanication -------")); + + /* Do NOT use explicit port mapping here: + * VPR added a prefix of "out_" to the output ports of input benchmark + */ + print_verilog_testbench_benchmark_instance(fp, reference_verilog_top_name, + std::string(TOP_TESTBENCH_REFERENCE_INSTANCE_NAME), + std::string(), + std::string(), + std::string(TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX), L_logical_blocks, + false); + + print_verilog_comment(fp, std::string("----- End reference Benchmark Instanication -------")); + + /* Add an empty line as splitter */ + fp << std::endl; + + /* Condition ends for the benchmark instanciation */ + print_verilog_endif(fp); + + /* Add an empty line as splitter */ + fp << std::endl; +} + +/******************************************************************** + * Print tasks (processes) in Verilog format, + * which is very useful in generating stimuli for each clock cycle + * This function is tuned for configuration-chain manipulation: + * During each programming cycle, we feed the input of scan chain with a memory bit + *******************************************************************/ +static +void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fstream& fp) { + + /* Validate the file stream */ + check_file_handler(fp); + + BasicPort prog_clock_port(std::string(top_tb_prog_clock_port_name), 1); + BasicPort cc_head_port(std::string(TOP_TESTBENCH_CONFIG_CHAIN_HEAD_PORT_NAME), 1); + BasicPort cc_head_value(std::string(TOP_TESTBENCH_CONFIG_CHAIN_HEAD_PORT_NAME) + std::string("_val"), 1); + + /* Add an empty line as splitter */ + fp << std::endl; + + /* Feed the scan-chain input at each falling edge of programming clock + * It aims at avoid racing the programming clock (scan-chain data changes at the rising edge). + */ + print_verilog_comment(fp, std::string("----- Task: input values during a programming clock cycle -----")); + fp << "task " << std::string(TOP_TESTBENCH_CC_PROG_TASK_NAME) << ";" << std::endl; + fp << generate_verilog_port(VERILOG_PORT_INPUT, cc_head_value) << ";" << std::endl; + fp << "\tbegin" << std::endl; + fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl; + fp << "\t\t"; + print_verilog_wire_connection(fp, cc_head_port, cc_head_value, false); + fp << "\tend" << std::endl; + fp << "endtask" << std::endl; + + /* Add an empty line as splitter */ + fp << std::endl; +} + +/******************************************************************** + * Print tasks, which is very useful in generating stimuli for each clock cycle + *******************************************************************/ +static +void print_verilog_top_testbench_load_bitstream_task(std::fstream& fp, + const e_sram_orgz& sram_orgz_type) { + switch (sram_orgz_type) { + case SPICE_SRAM_STANDALONE: + break; + case SPICE_SRAM_SCAN_CHAIN: + print_verilog_top_testbench_load_bitstream_task_configuration_chain(fp); + break; + case SPICE_SRAM_MEMORY_BANK: + /* TODO: + dump_verilog_top_testbench_stimuli_serial_version_tasks_memory_bank(cur_sram_orgz_info, fp); + */ + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid type of SRAM organization!\n", + __FILE__, __LINE__); + exit(1); + } +} + +/******************************************************************** + * Print generatic input stimuli for the top testbench + * include: + * 1. configuration done signal + * 2. programming clock + * 3. operating clock + * 4. programming reset signal + * 5. programming set signal + * 6. reset signal + * 7. set signal + *******************************************************************/ +static +void print_verilog_top_testbench_generic_stimulus(std::fstream& fp, + const size_t& num_config_clock_cycles, + const float& prog_clock_period, + const float& op_clock_period, + const float& timescale) { + /* Validate the file stream */ + check_file_handler(fp); + + print_verilog_comment(fp, std::string("----- Number of clock cycles in configuration phase: " + std::to_string(num_config_clock_cycles) + " -----")); + + BasicPort config_done_port(std::string(top_tb_config_done_port_name), 1); + + BasicPort op_clock_port(std::string(top_tb_op_clock_port_name), 1); + BasicPort op_clock_register_port(std::string(std::string(top_tb_op_clock_port_name) + std::string(top_tb_clock_reg_postfix)), 1); + + BasicPort prog_clock_port(std::string(top_tb_prog_clock_port_name), 1); + BasicPort prog_clock_register_port(std::string(std::string(top_tb_prog_clock_port_name) + std::string(top_tb_clock_reg_postfix)), 1); + + BasicPort prog_reset_port(std::string(top_tb_prog_reset_port_name), 1); + BasicPort prog_set_port(std::string(top_tb_prog_set_port_name), 1); + + BasicPort reset_port(std::string(top_tb_reset_port_name), 1); + BasicPort set_port(std::string(top_tb_set_port_name), 1); + + /* Generate stimuli waveform for configuration done signals */ + print_verilog_comment(fp, "----- Begin configuration done signal generation -----"); + print_verilog_pulse_stimuli(fp, config_done_port, + 0, /* Initial value */ + num_config_clock_cycles * prog_clock_period / timescale, 1); + print_verilog_comment(fp, "----- End configuration done signal generation -----"); + fp << std::endl; + + /* Generate stimuli waveform for programming clock signals */ + print_verilog_comment(fp, "----- Begin raw programming clock signal generation -----"); + print_verilog_clock_stimuli(fp, prog_clock_register_port, + 0, /* Initial value */ + 0.5 * prog_clock_period / timescale, + std::string()); + print_verilog_comment(fp, "----- End raw programming clock signal generation -----"); + fp << std::endl; + + /* Programming clock should be only enabled during programming phase. + * When configuration is done (config_done is enabled), programming clock should be always zero. + */ + print_verilog_comment(fp, std::string("----- Actual programming clock is triggered only when " + config_done_port.get_name() + " and " + prog_reset_port.get_name() + " are disabled -----")); + fp << "\tassign " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port); + fp << " = " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_register_port); + fp << " & (~" << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port) << ")"; + fp << " & (~" << generate_verilog_port(VERILOG_PORT_CONKT, prog_reset_port) << ")"; + fp << ";" << std::endl; + + fp << std::endl; + + /* Generate stimuli waveform for operating clock signals */ + print_verilog_comment(fp, "----- Begin raw operating clock signal generation -----"); + print_verilog_clock_stimuli(fp, op_clock_register_port, + 0, /* Initial value */ + 0.5 * op_clock_period / timescale, + std::string("~" + reset_port.get_name())); + print_verilog_comment(fp, "----- End raw operating clock signal generation -----"); + + /* Operation clock should be enabled after programming phase finishes. + * Before configuration is done (config_done is enabled), operation clock should be always zero. + */ + print_verilog_comment(fp, std::string("----- Actual operating clock is triggered only when " + config_done_port.get_name() + " is enabled -----")); + fp << "\tassign " << generate_verilog_port(VERILOG_PORT_CONKT, op_clock_port); + fp << " = " << generate_verilog_port(VERILOG_PORT_CONKT, op_clock_register_port); + fp << " & (~" << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port) << ")"; + fp << ";" << std::endl; + + fp << std::endl; + + /* Reset signal for configuration circuit: + * only enable during the first clock cycle in programming phase + */ + print_verilog_comment(fp, "----- Begin programming reset signal generation -----"); + print_verilog_pulse_stimuli(fp, prog_reset_port, + 1, /* Initial value */ + prog_clock_period / timescale, 0); + print_verilog_comment(fp, "----- End programming reset signal generation -----"); + + fp << std::endl; + + /* Programming set signal for configuration circuit : always disabled */ + print_verilog_comment(fp, "----- Begin programming set signal generation: always disabled -----"); + print_verilog_pulse_stimuli(fp, prog_set_port, + 0, /* Initial value */ + prog_clock_period / timescale, 0); + print_verilog_comment(fp, "----- End programming set signal generation: always disabled -----"); + + fp << std::endl; + + /* Operating reset signals: only enabled during the first clock cycle in operation phase */ + std::vector reset_pulse_widths; + reset_pulse_widths.push_back(op_clock_period / timescale); + reset_pulse_widths.push_back(2 * op_clock_period / timescale); + + std::vector reset_flip_values; + reset_flip_values.push_back(1); + reset_flip_values.push_back(0); + + print_verilog_comment(fp, "----- Begin operating reset signal generation -----"); + print_verilog_comment(fp, "----- Reset signal is enabled until the first clock cycle in operation phase -----"); + print_verilog_pulse_stimuli(fp, reset_port, + 1, + reset_pulse_widths, + reset_flip_values, + config_done_port.get_name()); + print_verilog_comment(fp, "----- End operating reset signal generation -----"); + + /* Operating set signal for configuration circuit : always disabled */ + print_verilog_comment(fp, "----- Begin operating set signal generation: always disabled -----"); + print_verilog_pulse_stimuli(fp, set_port, + 0, /* Initial value */ + op_clock_period / timescale, 0); + print_verilog_comment(fp, "----- End operating set signal generation: always disabled -----"); + + fp << std::endl; +} + +/******************************************************************** + * Print stimulus for a FPGA fabric with a configuration chain protocol + * where configuration bits are programming in serial (one by one) + * Task list: + * 1. For clock signal, we should create voltage waveforms for two types of clock signals: + * a. operation clock + * b. programming clock + * 2. For Set/Reset, we reset the chip after programming phase ends + * and before operation phase starts + * 3. For input/output clb nets (mapped to I/O grids), + * we should create voltage waveforms only after programming phase + *******************************************************************/ +static +void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp, + const BitstreamManager& bitstream_manager, + const std::vector& fabric_bitstream) { + /* Validate the file stream */ + check_file_handler(fp); + + /* Initial value should be the first configuration bits + * In the rest of programming cycles, + * configuration bits are fed at the falling edge of programming clock. + * We do not care the value of scan_chain head during the first programming cycle + * It is reset anyway + */ + BasicPort config_chain_head_port(std::string(TOP_TESTBENCH_CONFIG_CHAIN_HEAD_PORT_NAME), 1); + std::vector initial_values(config_chain_head_port.get_width(), 0); + + print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----"); + fp << "initial" << std::endl; + fp << "\tbegin" << std::endl; + print_verilog_comment(fp, "----- Configuration chain default input -----"); + fp << "\t"; + print_verilog_wire_constant_values(fp, config_chain_head_port, initial_values); + fp << std::endl; + + /* Attention: the configuration chain protcol requires the last configuration bit is fed first + * We will visit the fabric bitstream in a reverse way + */ + std::vector cc_bitstream = fabric_bitstream; + std::reverse(cc_bitstream.begin(), cc_bitstream.end()); + for (const ConfigBitId& bit_id : cc_bitstream) { + fp << "\t\t" << std::string(TOP_TESTBENCH_CC_PROG_TASK_NAME); + fp << "(1'b" << (size_t)bitstream_manager.bit_value(bit_id) << ");" << std::endl; + } + fp << "\tend" << std::endl; + print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----"); +} + +/******************************************************************** + * Generate the stimuli for the top-level testbench + * The simulation consists of two phases: configuration phase and operation phase + * Configuration bits are loaded serially. + * This is actually what we do for a physical FPGA + *******************************************************************/ +static +void print_verilog_top_testbench_bitstream(std::fstream& fp, + const e_sram_orgz& sram_orgz_type, + const BitstreamManager& bitstream_manager, + const std::vector& fabric_bitstream) { + /* Branch on the type of configuration protocol */ + switch (sram_orgz_type) { + case SPICE_SRAM_STANDALONE: + /* TODO */ + break; + case SPICE_SRAM_SCAN_CHAIN: + print_verilog_top_testbench_configuration_chain_bitstream(fp, bitstream_manager, fabric_bitstream); + break; + case SPICE_SRAM_MEMORY_BANK: + /* TODO */ + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid SRAM organization type!\n", + __FILE__, __LINE__); + exit(1); + } +} + +/******************************************************************** + * The top-level function to generate a testbench, in order to verify: + * 1. Configuration phase of the FPGA fabric, where the bitstream is + * loaded to the configuration protocol of the FPGA fabric + * 2. Operating phase of the FPGA fabric, where input stimuli are + * fed to the I/Os of the FPGA fabric + * +----------+ + * | FPGA | +------------+ + * +----->| Fabric |------>| | + * | | | | | + * | +----------+ | | + * | | Output | + * random_input_vectors -----+ | Vector |---->Functional correct? + * | | Comparator | + * | +-----------+ | | + * | | Input | | | + * +----->| Benchmark |----->| | + * +-----------+ +------------+ + * + *******************************************************************/ +void print_verilog_top_testbench(const ModuleManager& module_manager, + const BitstreamManager& bitstream_manager, + const std::vector& fabric_bitstream, + const e_sram_orgz& sram_orgz_type, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports, + const std::vector& L_logical_blocks, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, + const std::string& circuit_name, + const std::string& verilog_fname, + const std::string& verilog_dir, + const std::string& reference_benchmark_file, + const t_spice_params& simulation_parameters) { + vpr_printf(TIO_MESSAGE_INFO, + "Writing Autocheck Testbench for FPGA Top-level Verilog netlist for %s...", + circuit_name.c_str()); + + /* Start time count */ + clock_t t_start = clock(); + + /* Create the file stream */ + std::fstream fp; + fp.open(verilog_fname, std::fstream::out | std::fstream::trunc); + + /* Validate the file stream */ + check_file_handler(fp); + + /* Generate a brief description on the Verilog file*/ + std::string title = std::string("FPGA Verilog Testbench for Top-level netlist of Design: ") + circuit_name; + print_verilog_file_header(fp, title); + + /* Print preprocessing flags and external netlists */ + print_verilog_include_defines_preproc_file(fp, verilog_dir); + + /* Include reference benchmark file */ + print_verilog_include_netlist(fp, reference_benchmark_file); + + /* Find the top_module */ + ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name()); + VTR_ASSERT(true == module_manager.valid_module_id(top_module)); + + /* Start of testbench */ + //dump_verilog_top_auto_testbench_ports(fp, cur_sram_orgz_info, circuit_name, fpga_verilog_opts); + print_verilog_top_testbench_ports(fp, module_manager, top_module, + sram_orgz_type, circuit_name); + + /* Find the clock period */ + float prog_clock_period = (1./simulation_parameters.stimulate_params.prog_clock_freq); + float op_clock_period = (1./simulation_parameters.stimulate_params.op_clock_freq); + /* Estimate the number of configuration clock cycles + * by traversing the linked-list and count the number of SRAM=1 or BL=1&WL=1 in it. + * We plus 1 additional config clock cycle here because we need to reset everything during the first clock cycle + */ + size_t num_config_clock_cycles = 1 + fabric_bitstream.size(); + + /* Generate stimuli for general control signals */ + print_verilog_top_testbench_generic_stimulus(fp, + num_config_clock_cycles, + prog_clock_period, + op_clock_period, + verilog_sim_timescale); + + /* Generate stimuli for global ports or connect them to existed signals */ + print_verilog_top_testbench_global_ports_stimuli(fp, + module_manager, top_module, + circuit_lib, global_ports); + + /* Instanciate FPGA top-level module */ + print_verilog_testbench_fpga_instance(fp, module_manager, top_module, + std::string(TOP_TESTBENCH_FPGA_INSTANCE_NAME)); + + /* Connect I/Os to benchmark I/Os or constant driver */ + print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module, + L_logical_blocks, device_size, L_grids, + L_blocks, + std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX), + (size_t)verilog_default_signal_init_value); + + /* Instanciate input benchmark */ + print_verilog_top_testbench_benchmark_instance(fp, + circuit_name, + L_logical_blocks); + + /* Print tasks used for loading bitstreams */ + print_verilog_top_testbench_load_bitstream_task(fp, sram_orgz_type); + + /* load bitstream to FPGA fabric in a configuration phase */ + print_verilog_top_testbench_bitstream(fp, sram_orgz_type, + bitstream_manager, fabric_bitstream); + + /* Preparation: find all the clock ports */ + std::vector clock_port_names = find_benchmark_clock_port_name(L_logical_blocks); + + /* Add output autocheck */ + print_verilog_testbench_check(fp, + std::string(autochecked_simulation_flag), + std::string(TOP_TESTBENCH_SIM_START_PORT_NAME), + std::string(TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX), + std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX), + std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX), + std::string(TOP_TESTBENCH_ERROR_COUNTER), + L_logical_blocks, clock_port_names, std::string(top_tb_op_clock_port_name)); + + /* Find simulation time */ + float simulation_time = find_simulation_time_period(verilog_sim_timescale, + num_config_clock_cycles, + 1./simulation_parameters.stimulate_params.prog_clock_freq, + simulation_parameters.meas_params.sim_num_clock_cycle, + 1./simulation_parameters.stimulate_params.op_clock_freq); + + + /* Add Icarus requirement */ + print_verilog_timeout_and_vcd(fp, + std::string(icarus_simulator_flag), + std::string(circuit_name + std::string(modelsim_autocheck_testbench_module_postfix)), + std::string(circuit_name + std::string("_formal.vcd")), + std::string(TOP_TESTBENCH_SIM_START_PORT_NAME), + std::string(TOP_TESTBENCH_ERROR_COUNTER), + (int)simulation_time); + + + /* Testbench ends*/ + print_verilog_module_end(fp, std::string(circuit_name) + std::string(modelsim_autocheck_testbench_module_postfix)); + + /* Close the file stream */ + 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); +} From d7bbae76a4bd5360e8a177ccfc5cbdc5b7b6ace7 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 3 Nov 2019 20:20:14 -0700 Subject: [PATCH 21/68] adding stimuli to benchmark inputs in top-level testbench --- .../verilog_formal_random_top_testbench.cpp | 103 +----------------- .../verilog/verilog_testbench_utils.cpp | 103 ++++++++++++++++++ .../verilog/verilog_testbench_utils.h | 7 ++ .../verilog/verilog_top_testbench.cpp | 5 + 4 files changed, 118 insertions(+), 100 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp index 362992bc2..880c06ad5 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp @@ -223,105 +223,6 @@ void print_verilog_random_testbench_fpga_instance(std::fstream& fp, fp << std::endl; } -/******************************************************************** - * Generate random stimulus for the input ports - *******************************************************************/ -static -void print_verilog_top_random_stimuli(std::fstream& fp, - const t_spice_params& simulation_parameters, - const std::vector& L_logical_blocks, - const std::vector& clock_port_names) { - /* Validate the file stream */ - check_file_handler(fp); - - print_verilog_comment(fp, std::string("----- Initialization -------")); - - fp << "\tinitial begin" << std::endl; - /* Create clock stimuli */ - BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME)); - fp << "\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << " <= 1'b0;" << std::endl; - fp << "\t\twhile(1) begin" << std::endl; - fp << "\t\t\t#" << std::setprecision(2) << ((0.5/simulation_parameters.stimulate_params.op_clock_freq)/verilog_sim_timescale) << std::endl; - fp << "\t\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port); - fp << " <= !"; - fp << generate_verilog_port(VERILOG_PORT_CONKT, clock_port); - fp << ";" << std::endl; - fp << "\t\tend" << std::endl; - - /* Add an empty line as splitter */ - fp << std::endl; - - for (const t_logical_block& lb : L_logical_blocks) { - /* Bypass non-I/O logical blocks ! */ - if ( (VPACK_INPAD != lb.type) && (VPACK_OUTPAD != lb.type) ) { - continue; - } - - /* Clock ports will be initialized later */ - if ( (VPACK_INPAD == lb.type) && (FALSE == lb.is_clock) ) { - fp << "\t\t" << std::string(lb.name) << " <= 1'b0;" << std::endl; - } - } - - /* Add an empty line as splitter */ - fp << std::endl; - - /* Set 0 to registers for checking flags */ - for (const t_logical_block& lb : L_logical_blocks) { - /* We care only those logic blocks which are input I/Os */ - if (VPACK_OUTPAD != lb.type) { - continue; - } - - /* Each logical block assumes a single-width port */ - BasicPort output_port(std::string(std::string(lb.name) + std::string(CHECKFLAG_PORT_POSTFIX)), 1); - fp << "\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << " <= 1'b0;" << std::endl; - } - - fp << "\tend" << std::endl; - /* Finish initialization */ - - /* Add an empty line as splitter */ - fp << std::endl; - - // Not ready yet to determine if input is reset -/* - fprintf(fp, "//----- Reset Stimulis\n"); - fprintf(fp, " initial begin\n"); - fprintf(fp, " #%.3f\n",(rand() % 10) + 0.001); - fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name); - fprintf(fp, " #%.3f\n",(rand() % 10) + 0.001); - fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name); - fprintf(fp, " while(1) begin\n"); - fprintf(fp, " #%.3f\n", (rand() % 15) + 0.5); - fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name); - fprintf(fp, " #%.3f\n", (rand() % 10000) + 200); - fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name); - fprintf(fp, " end\n"); - fprintf(fp, " end\n\n"); -*/ - - print_verilog_comment(fp, std::string("----- Input Stimulus -------")); - fp << "\talways@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << ") begin" << std::endl; - - for (const t_logical_block& lb : L_logical_blocks) { - /* Bypass non-I/O logical blocks ! */ - if ( (VPACK_INPAD != lb.type) && (VPACK_OUTPAD != lb.type) ) { - continue; - } - - /* Clock ports will be initialized later */ - if ( (VPACK_INPAD == lb.type) && (FALSE == lb.is_clock) ) { - fp << "\t\t" << std::string(lb.name) << " <= $random;" << std::endl; - } - } - - fp << "\tend" << std::endl; - - /* Add an empty line as splitter */ - fp << std::endl; -} - /********************************************************************* * Top-level function in this file: * Create a Verilog testbench using random input vectors @@ -391,7 +292,9 @@ void print_verilog_random_top_testbench(const std::string& circuit_name, print_verilog_top_random_testbench_benchmark_instance(fp, circuit_name, L_logical_blocks); /* Add stimuli for reset, set, clock and iopad signals */ - print_verilog_top_random_stimuli(fp, simulation_parameters, L_logical_blocks, clock_port_names); + print_verilog_testbench_random_stimuli(fp, simulation_parameters, L_logical_blocks, + std::string(CHECKFLAG_PORT_POSTFIX), + clock_port_names, std::string(DEFAULT_CLOCK_NAME)); print_verilog_testbench_check(fp, std::string(autochecked_simulation_flag), diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp index d0b5e6b78..926e247d5 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp @@ -5,6 +5,8 @@ * Note: please try to avoid using global variables in this file * so that we can make it free to use anywhere *******************************************************************/ +#include + #include "vtr_assert.h" #include "device_port.h" @@ -332,3 +334,104 @@ void print_verilog_testbench_check(std::fstream& fp, /* Add an empty line as splitter */ fp << std::endl; } + +/******************************************************************** + * Generate random stimulus for the input ports + *******************************************************************/ +void print_verilog_testbench_random_stimuli(std::fstream& fp, + const t_spice_params& simulation_parameters, + const std::vector& L_logical_blocks, + const std::string& check_flag_port_postfix, + const std::vector& clock_port_names, + const std::string& default_clock_name) { + /* Validate the file stream */ + check_file_handler(fp); + + print_verilog_comment(fp, std::string("----- Initialization -------")); + + fp << "\tinitial begin" << std::endl; + /* Create clock stimuli */ + BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, default_clock_name); + fp << "\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << " <= 1'b0;" << std::endl; + fp << "\t\twhile(1) begin" << std::endl; + fp << "\t\t\t#" << std::setprecision(2) << ((0.5/simulation_parameters.stimulate_params.op_clock_freq)/verilog_sim_timescale) << std::endl; + fp << "\t\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port); + fp << " <= !"; + fp << generate_verilog_port(VERILOG_PORT_CONKT, clock_port); + fp << ";" << std::endl; + fp << "\t\tend" << std::endl; + + /* Add an empty line as splitter */ + fp << std::endl; + + for (const t_logical_block& lb : L_logical_blocks) { + /* Bypass non-I/O logical blocks ! */ + if ( (VPACK_INPAD != lb.type) && (VPACK_OUTPAD != lb.type) ) { + continue; + } + + /* Clock ports will be initialized later */ + if ( (VPACK_INPAD == lb.type) && (FALSE == lb.is_clock) ) { + fp << "\t\t" << std::string(lb.name) << " <= 1'b0;" << std::endl; + } + } + + /* Add an empty line as splitter */ + fp << std::endl; + + /* Set 0 to registers for checking flags */ + for (const t_logical_block& lb : L_logical_blocks) { + /* We care only those logic blocks which are input I/Os */ + if (VPACK_OUTPAD != lb.type) { + continue; + } + + /* Each logical block assumes a single-width port */ + BasicPort output_port(std::string(std::string(lb.name) + check_flag_port_postfix), 1); + fp << "\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << " <= 1'b0;" << std::endl; + } + + fp << "\tend" << std::endl; + /* Finish initialization */ + + /* Add an empty line as splitter */ + fp << std::endl; + + // Not ready yet to determine if input is reset +/* + fprintf(fp, "//----- Reset Stimulis\n"); + fprintf(fp, " initial begin\n"); + fprintf(fp, " #%.3f\n",(rand() % 10) + 0.001); + fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name); + fprintf(fp, " #%.3f\n",(rand() % 10) + 0.001); + fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name); + fprintf(fp, " while(1) begin\n"); + fprintf(fp, " #%.3f\n", (rand() % 15) + 0.5); + fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name); + fprintf(fp, " #%.3f\n", (rand() % 10000) + 200); + fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name); + fprintf(fp, " end\n"); + fprintf(fp, " end\n\n"); +*/ + + print_verilog_comment(fp, std::string("----- Input Stimulus -------")); + fp << "\talways@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << ") begin" << std::endl; + + for (const t_logical_block& lb : L_logical_blocks) { + /* Bypass non-I/O logical blocks ! */ + if ( (VPACK_INPAD != lb.type) && (VPACK_OUTPAD != lb.type) ) { + continue; + } + + /* Clock ports will be initialized later */ + if ( (VPACK_INPAD == lb.type) && (FALSE == lb.is_clock) ) { + fp << "\t\t" << std::string(lb.name) << " <= $random;" << std::endl; + } + } + + fp << "\tend" << std::endl; + + /* Add an empty line as splitter */ + fp << std::endl; +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h index b344bee5f..729d28a27 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h @@ -54,4 +54,11 @@ void print_verilog_testbench_check(std::fstream& fp, const std::vector& clock_port_names, const std::string& default_clock_name); +void print_verilog_testbench_random_stimuli(std::fstream& fp, + const t_spice_params& simulation_parameters, + const std::vector& L_logical_blocks, + const std::string& check_flag_port_postfix, + const std::vector& clock_port_names, + const std::string& default_clock_name); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp index febbf37a0..8a13a7433 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp @@ -785,6 +785,11 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, /* Preparation: find all the clock ports */ std::vector clock_port_names = find_benchmark_clock_port_name(L_logical_blocks); + /* Add stimuli for reset, set, clock and iopad signals */ + print_verilog_testbench_random_stimuli(fp, simulation_parameters, L_logical_blocks, + std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX), + clock_port_names, std::string(top_tb_op_clock_port_name)); + /* Add output autocheck */ print_verilog_testbench_check(fp, std::string(autochecked_simulation_flag), From 3274a49779e85f8c36c5db297fb7d521ab1e1337 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 4 Nov 2019 12:08:36 -0700 Subject: [PATCH 22/68] fine tuning top testbench and getting ready for testing --- .../verilog_formal_random_top_testbench.cpp | 10 +++- .../verilog/verilog_preconfig_top_module.cpp | 1 + .../verilog/verilog_testbench_utils.cpp | 56 ++++++++++++++----- .../verilog/verilog_testbench_utils.h | 11 ++-- .../verilog/verilog_top_testbench.cpp | 44 ++++++++++----- .../fpga_x2p/verilog/verilog_writer_utils.cpp | 38 +++++++++---- 6 files changed, 114 insertions(+), 46 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp index 880c06ad5..a18659eef 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp @@ -291,10 +291,14 @@ void print_verilog_random_top_testbench(const std::string& circuit_name, /* Call defined benchmark */ print_verilog_top_random_testbench_benchmark_instance(fp, circuit_name, L_logical_blocks); + /* Find clock port to be used */ + BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME)); + /* Add stimuli for reset, set, clock and iopad signals */ - print_verilog_testbench_random_stimuli(fp, simulation_parameters, L_logical_blocks, - std::string(CHECKFLAG_PORT_POSTFIX), - clock_port_names, std::string(DEFAULT_CLOCK_NAME)); + print_verilog_testbench_clock_stimuli(fp, simulation_parameters, + clock_port); + print_verilog_testbench_random_stimuli(fp, L_logical_blocks, + std::string(CHECKFLAG_PORT_POSTFIX), clock_port); print_verilog_testbench_check(fp, std::string(autochecked_simulation_flag), diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp index 6f0b7b43e..9147cc053 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp @@ -422,6 +422,7 @@ void print_verilog_preconfig_top_module(const ModuleManager& module_manager, L_logical_blocks, device_size, L_grids, L_blocks, std::string(formal_verification_top_module_port_postfix), + std::string(formal_verification_top_module_port_postfix), (size_t)verilog_default_signal_init_value); /* Assign FPGA internal SRAM/Memory ports to bitstream values */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp index 926e247d5..7d519d543 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp @@ -108,7 +108,8 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, const vtr::Point& device_size, const std::vector>& L_grids, const std::vector& L_blocks, - const std::string& io_port_name_postfix, + const std::string& io_input_port_name_postfix, + const std::string& io_output_port_name_postfix, const size_t& unused_io_value) { /* Validate the file stream */ check_file_handler(fp); @@ -140,14 +141,21 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, VTR_ASSERT(io_index < module_mapped_io_port.get_width()); module_mapped_io_port.set_width(io_index, io_index); - /* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always has a size of 1 */ - BasicPort benchmark_io_port(std::string(std::string(io_lb.name)+ io_port_name_postfix), 1); - - print_verilog_comment(fp, std::string("----- Blif Benchmark inout " + std::string(io_lb.name) + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----")); + /* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always has a size of 1 + * In addition, the input and output ports may have different postfix in naming + * due to verification context! Here, we give full customization on naming + */ + BasicPort benchmark_io_port; if (VPACK_INPAD == io_lb.type) { + benchmark_io_port.set_name(std::string(std::string(io_lb.name) + io_input_port_name_postfix)); + benchmark_io_port.set_width(1); + print_verilog_comment(fp, std::string("----- Blif Benchmark input " + std::string(io_lb.name) + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----")); print_verilog_wire_connection(fp, module_mapped_io_port, benchmark_io_port, false); } else { VTR_ASSERT(VPACK_OUTPAD == io_lb.type); + benchmark_io_port.set_name(std::string(std::string(io_lb.name) + io_output_port_name_postfix)); + benchmark_io_port.set_width(1); + print_verilog_comment(fp, std::string("----- Blif Benchmark output " + std::string(io_lb.name) + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----")); print_verilog_wire_connection(fp, benchmark_io_port, module_mapped_io_port, false); } @@ -336,33 +344,51 @@ void print_verilog_testbench_check(std::fstream& fp, } /******************************************************************** - * Generate random stimulus for the input ports + * Generate random stimulus for the clock port + * This function is designed to drive the clock port of a benchmark module + * If there is no clock port found, we will give a default clock name + * In such case, this clock will not be wired to the benchmark module + * but be only used as a synchronizer in verification *******************************************************************/ -void print_verilog_testbench_random_stimuli(std::fstream& fp, - const t_spice_params& simulation_parameters, - const std::vector& L_logical_blocks, - const std::string& check_flag_port_postfix, - const std::vector& clock_port_names, - const std::string& default_clock_name) { +void print_verilog_testbench_clock_stimuli(std::fstream& fp, + const t_spice_params& simulation_parameters, + const BasicPort& clock_port) { /* Validate the file stream */ check_file_handler(fp); - print_verilog_comment(fp, std::string("----- Initialization -------")); + print_verilog_comment(fp, std::string("----- Clock Initialization -------")); fp << "\tinitial begin" << std::endl; /* Create clock stimuli */ - BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, default_clock_name); fp << "\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << " <= 1'b0;" << std::endl; fp << "\t\twhile(1) begin" << std::endl; - fp << "\t\t\t#" << std::setprecision(2) << ((0.5/simulation_parameters.stimulate_params.op_clock_freq)/verilog_sim_timescale) << std::endl; + fp << "\t\t\t#" << std::setprecision(10) << ((0.5/simulation_parameters.stimulate_params.op_clock_freq)/verilog_sim_timescale) << std::endl; fp << "\t\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port); fp << " <= !"; fp << generate_verilog_port(VERILOG_PORT_CONKT, clock_port); fp << ";" << std::endl; fp << "\t\tend" << std::endl; + fp << "\tend" << std::endl; + /* Add an empty line as splitter */ fp << std::endl; +} + +/******************************************************************** + * Generate random stimulus for the input ports (non-clock signals) + * For clock signals, please use print_verilog_testbench_clock_stimuli + *******************************************************************/ +void print_verilog_testbench_random_stimuli(std::fstream& fp, + const std::vector& L_logical_blocks, + const std::string& check_flag_port_postfix, + const BasicPort& clock_port) { + /* Validate the file stream */ + check_file_handler(fp); + + print_verilog_comment(fp, std::string("----- Input Initialization -------")); + + fp << "\tinitial begin" << std::endl; for (const t_logical_block& lb : L_logical_blocks) { /* Bypass non-I/O logical blocks ! */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h index 729d28a27..3c67f6eaa 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h @@ -29,7 +29,8 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp, const vtr::Point& device_size, const std::vector>& L_grids, const std::vector& L_blocks, - const std::string& io_port_name_postfix, + const std::string& io_input_port_name_postfix, + const std::string& io_output_port_name_postfix, const size_t& unused_io_value); void print_verilog_timeout_and_vcd(std::fstream& fp, @@ -54,11 +55,13 @@ void print_verilog_testbench_check(std::fstream& fp, const std::vector& clock_port_names, const std::string& default_clock_name); +void print_verilog_testbench_clock_stimuli(std::fstream& fp, + const t_spice_params& simulation_parameters, + const BasicPort& clock_port); + void print_verilog_testbench_random_stimuli(std::fstream& fp, - const t_spice_params& simulation_parameters, const std::vector& L_logical_blocks, const std::string& check_flag_port_postfix, - const std::vector& clock_port_names, - const std::string& default_clock_name); + const BasicPort& clock_port); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp index 8a13a7433..f10aecc3d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp @@ -29,12 +29,10 @@ constexpr char* TOP_TESTBENCH_REFERENCE_INSTANCE_NAME = "REF_DUT"; constexpr char* TOP_TESTBENCH_FPGA_INSTANCE_NAME = "FPGA_DUT"; constexpr char* TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX = "_benchmark"; -constexpr char* TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX = "_verification"; +constexpr char* TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX = "_fpga"; constexpr char* TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX = "_flag"; -constexpr char* TOP_TESTBENCH_CONFIG_CHAIN_HEAD_PORT_NAME = "cc_in"; -constexpr char* TOP_TESTBENCH_CONFIG_CHAIN_TAIL_PORT_NAME = "cc_out"; constexpr char* TOP_TESTBENCH_CC_PROG_TASK_NAME = "prog_cycle_task"; constexpr char* TOP_TESTBENCH_SIM_START_PORT_NAME = "sim_start"; @@ -52,13 +50,13 @@ void print_verilog_top_testbench_config_chain_port(std::fstream& fp) { /* Print the head of configuraion-chains here */ print_verilog_comment(fp, std::string("---- Configuration-chain head -----")); - BasicPort config_chain_head_port(std::string(TOP_TESTBENCH_CONFIG_CHAIN_HEAD_PORT_NAME), 1); + BasicPort config_chain_head_port(generate_configuration_chain_head_name(), 1); fp << generate_verilog_port(VERILOG_PORT_REG, config_chain_head_port) << ";" << std::endl; /* Print the tail of configuration-chains here */ print_verilog_comment(fp, std::string("---- Configuration-chain tail -----")); - BasicPort config_chain_tail_port(std::string(TOP_TESTBENCH_CONFIG_CHAIN_TAIL_PORT_NAME), 1); - fp << generate_verilog_port(VERILOG_PORT_REG, config_chain_tail_port) << ";" << std::endl; + BasicPort config_chain_tail_port(generate_configuration_chain_tail_name(), 1); + fp << generate_verilog_port(VERILOG_PORT_WIRE, config_chain_tail_port) << ";" << std::endl; } /******************************************************************** @@ -411,8 +409,8 @@ void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fs check_file_handler(fp); BasicPort prog_clock_port(std::string(top_tb_prog_clock_port_name), 1); - BasicPort cc_head_port(std::string(TOP_TESTBENCH_CONFIG_CHAIN_HEAD_PORT_NAME), 1); - BasicPort cc_head_value(std::string(TOP_TESTBENCH_CONFIG_CHAIN_HEAD_PORT_NAME) + std::string("_val"), 1); + BasicPort cc_head_port(generate_configuration_chain_head_name(), 1); + BasicPort cc_head_value(generate_configuration_chain_head_name() + std::string("_val"), 1); /* Add an empty line as splitter */ fp << std::endl; @@ -425,8 +423,12 @@ void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fs fp << generate_verilog_port(VERILOG_PORT_INPUT, cc_head_value) << ";" << std::endl; fp << "\tbegin" << std::endl; fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl; - fp << "\t\t"; - print_verilog_wire_connection(fp, cc_head_port, cc_head_value, false); + fp << "\t\t\t"; + fp << generate_verilog_port(VERILOG_PORT_CONKT, cc_head_port); + fp << " = "; + fp << generate_verilog_port(VERILOG_PORT_CONKT, cc_head_value); + fp << ";" << std::endl; + fp << "\tend" << std::endl; fp << "endtask" << std::endl; @@ -499,7 +501,7 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp, print_verilog_comment(fp, "----- Begin configuration done signal generation -----"); print_verilog_pulse_stimuli(fp, config_done_port, 0, /* Initial value */ - num_config_clock_cycles * prog_clock_period / timescale, 1); + num_config_clock_cycles * prog_clock_period / timescale, 0); print_verilog_comment(fp, "----- End configuration done signal generation -----"); fp << std::endl; @@ -616,7 +618,7 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp, * We do not care the value of scan_chain head during the first programming cycle * It is reset anyway */ - BasicPort config_chain_head_port(std::string(TOP_TESTBENCH_CONFIG_CHAIN_HEAD_PORT_NAME), 1); + BasicPort config_chain_head_port(generate_configuration_chain_head_name(), 1); std::vector initial_values(config_chain_head_port.get_width(), 0); print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----"); @@ -636,6 +638,19 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp, fp << "\t\t" << std::string(TOP_TESTBENCH_CC_PROG_TASK_NAME); fp << "(1'b" << (size_t)bitstream_manager.bit_value(bit_id) << ");" << std::endl; } + + /* Raise the flag of configuration done when bitstream loading is complete */ + BasicPort prog_clock_port(std::string(top_tb_prog_clock_port_name), 1); + fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl; + + BasicPort config_done_port(std::string(top_tb_config_done_port_name), 1); + fp << "\t\t\t"; + fp << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port); + fp << " <= "; + std::vector config_done_enable_values(config_done_port.get_width(), 1); + fp << generate_verilog_constant_values(config_done_enable_values); + fp << ";" << std::endl; + fp << "\tend" << std::endl; print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----"); } @@ -767,6 +782,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module, L_logical_blocks, device_size, L_grids, L_blocks, + std::string(), std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX), (size_t)verilog_default_signal_init_value); @@ -786,9 +802,9 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, std::vector clock_port_names = find_benchmark_clock_port_name(L_logical_blocks); /* Add stimuli for reset, set, clock and iopad signals */ - print_verilog_testbench_random_stimuli(fp, simulation_parameters, L_logical_blocks, + print_verilog_testbench_random_stimuli(fp, L_logical_blocks, std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX), - clock_port_names, std::string(top_tb_op_clock_port_name)); + BasicPort(std::string(top_tb_op_clock_port_name), 1)); /* Add output autocheck */ print_verilog_testbench_check(fp, 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 d2593138b..20f7c6dd0 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 @@ -1234,13 +1234,17 @@ void print_verilog_pulse_stimuli(std::fstream& fp, fp << "\tbegin" << std::endl; fp << "\t"; std::vector initial_values(port.get_width(), initial_value); - print_verilog_wire_constant_values(fp, port, initial_values); + fp << "\t"; + fp << generate_verilog_port_constant_values(port, initial_values); + fp << ";" << std::endl; /* if flip_value is the same as initial value, we do not need to flip the signal ! */ if (flip_value != initial_value) { - fp << "\t" << "#" << std::setprecision(2) << pulse_width; + fp << "\t" << "#" << std::setprecision(10) << pulse_width; std::vector port_flip_values(port.get_width(), flip_value); - print_verilog_wire_constant_values(fp, port, port_flip_values); + fp << "\t"; + fp << generate_verilog_port_constant_values(port, port_flip_values); + fp << ";" << std::endl; } fp << "\tend" << std::endl; @@ -1274,7 +1278,9 @@ void print_verilog_pulse_stimuli(std::fstream& fp, fp << "\tbegin" << std::endl; fp << "\t"; std::vector initial_values(port.get_width(), initial_value); - print_verilog_wire_constant_values(fp, port, initial_values); + fp << "\t"; + fp << generate_verilog_port_constant_values(port, initial_values); + fp << ";" << std::endl; /* Set a wait condition if specified */ if (false == wait_condition.empty()) { @@ -1284,9 +1290,11 @@ void print_verilog_pulse_stimuli(std::fstream& fp, /* Number of flip conditions and values should match */ VTR_ASSERT(flip_values.size() == pulse_widths.size()); for (size_t ipulse = 0; ipulse < pulse_widths.size(); ++ipulse) { - fp << "\t" << "#" << std::setprecision(2) << pulse_widths[ipulse]; + fp << "\t" << "#" << std::setprecision(10) << pulse_widths[ipulse]; std::vector port_flip_value(port.get_width(), flip_values[ipulse]); - print_verilog_wire_constant_values(fp, port, port_flip_value); + fp << "\t"; + fp << generate_verilog_port_constant_values(port, port_flip_value); + fp << ";" << std::endl; } fp << "\tend" << std::endl; @@ -1318,9 +1326,12 @@ void print_verilog_clock_stimuli(std::fstream& fp, /* Config_done signal: indicate when configuration is finished */ fp << "initial" << std::endl; fp << "\tbegin" << std::endl; - fp << "\t"; + std::vector initial_values(port.get_width(), initial_value); - print_verilog_wire_constant_values(fp, port, initial_values); + fp << "\t\t"; + fp << generate_verilog_port_constant_values(port, initial_values); + fp << ";" << std::endl; + fp << "\tend" << std::endl; fp << "always"; @@ -1332,8 +1343,15 @@ void print_verilog_clock_stimuli(std::fstream& fp, } fp << "\tbegin" << std::endl; - fp << "\t\t" << "#" << std::setprecision(2) << pulse_width; - print_verilog_wire_connection(fp, port, port, true); + fp << "\t\t" << "#" << std::setprecision(10) << pulse_width; + + fp << "\t"; + fp << generate_verilog_port(VERILOG_PORT_CONKT, port); + fp << " = "; + fp << "~"; + fp << generate_verilog_port(VERILOG_PORT_CONKT, port); + fp << ";" << std::endl; + fp << "\tend" << std::endl; /* Print an empty line as splitter */ From 69bc858e62fca08730798a52fd6dedf436d45e28 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 4 Nov 2019 15:35:04 -0700 Subject: [PATCH 23/68] bring autocheck top testbench back to simulation deck, start testing --- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 5 +- .../verilog_formal_random_top_testbench.cpp | 89 ++------------- .../verilog/verilog_include_netlists.c | 22 ++-- .../verilog/verilog_testbench_utils.cpp | 101 ++++++++++++++++++ .../verilog/verilog_testbench_utils.h | 7 ++ .../verilog/verilog_top_testbench.cpp | 25 +++-- .../fpga_x2p/verilog/verilog_top_testbench.h | 1 - 7 files changed, 150 insertions(+), 100 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 1037106b0..eb6eadcca 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -448,18 +448,19 @@ void vpr_fpga_verilog(ModuleManager& module_manager, + std::string(chomped_circuit_name) + std::string(autocheck_top_testbench_verilog_file_postfix); /* TODO: this is an old function, to be shadowed */ + /* dump_verilog_autocheck_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, autocheck_top_testbench_file_path.c_str(), src_dir_path, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, *(Arch.spice)); + */ /* TODO: new function: to be tested */ print_verilog_top_testbench(module_manager, bitstream_manager, fabric_bitstream, sram_verilog_orgz_info->type, Arch.spice->circuit_lib, global_ports, L_logical_blocks, device_size, L_grids, L_blocks, std::string(chomped_circuit_name), - std::string(autocheck_top_testbench_file_path + std::string(".bak")), + autocheck_top_testbench_file_path, std::string(src_dir_path), - std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file), Arch.spice->spice_params); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp index a18659eef..26b86d7a1 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp @@ -61,94 +61,21 @@ void print_verilog_top_random_testbench_ports(std::fstream& fp, /* Print the declaration for the module */ fp << "module " << circuit_name << FORMAL_RANDOM_TOP_TESTBENCH_POSTFIX << ";" << std::endl; - /* Instantiate register for inputs stimulis */ - print_verilog_comment(fp, std::string("----- Shared inputs -------")); - for (const t_logical_block& lb : L_logical_blocks) { - /* We care only those logic blocks which are input I/Os */ - if (VPACK_INPAD != lb.type) { - continue; - } - - /* Each logical block assumes a single-width port */ - BasicPort input_port(std::string(lb.name), 1); - fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, input_port) << ";" << std::endl; - } - - /* Add an empty line as splitter */ - fp << std::endl; - /* Create a clock port if the benchmark does not have one! * The clock is used for counting and synchronizing input stimulus */ - if (0 == clock_port_names.size()) { - BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME)); - print_verilog_comment(fp, std::string("----- Default clock port is added here since benchmark does not contain one -------")); - fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, clock_port) << ";" << std::endl; - } + BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME)); + print_verilog_comment(fp, std::string("----- Default clock port is added here since benchmark does not contain one -------")); + fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, clock_port) << ";" << std::endl; /* Add an empty line as splitter */ fp << std::endl; - /* Instantiate wires for FPGA fabric outputs */ - print_verilog_comment(fp, std::string("----- FPGA fabric outputs -------")); - - for (const t_logical_block& lb : L_logical_blocks) { - /* We care only those logic blocks which are input I/Os */ - if (VPACK_OUTPAD != lb.type) { - continue; - } - - /* Each logical block assumes a single-width port */ - BasicPort output_port(std::string(std::string(lb.name) + std::string(FPGA_PORT_POSTFIX)), 1); - fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, output_port) << ";" << std::endl; - } - - /* Add an empty line as splitter */ - fp << std::endl; - - /* Benchmark is instanciated conditionally: only when a preprocessing flag is enable */ - print_verilog_preprocessing_flag(fp, std::string(autochecked_simulation_flag)); - - /* Add an empty line as splitter */ - fp << std::endl; - - /* Instantiate wire for benchmark output */ - print_verilog_comment(fp, std::string("----- Benchmark outputs -------")); - for (const t_logical_block& lb : L_logical_blocks) { - /* We care only those logic blocks which are input I/Os */ - if (VPACK_OUTPAD != lb.type) { - continue; - } - - /* Each logical block assumes a single-width port */ - BasicPort output_port(std::string(std::string(lb.name) + std::string(BENCHMARK_PORT_POSTFIX)), 1); - fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, output_port) << ";" << std::endl; - } - - /* Add an empty line as splitter */ - fp << std::endl; - - /* Instantiate register for output comparison */ - print_verilog_comment(fp, std::string("----- Output vectors checking flags -------")); - for (const t_logical_block& lb : L_logical_blocks) { - /* We care only those logic blocks which are input I/Os */ - if (VPACK_OUTPAD != lb.type) { - continue; - } - - /* Each logical block assumes a single-width port */ - BasicPort output_port(std::string(std::string(lb.name) + std::string(CHECKFLAG_PORT_POSTFIX)), 1); - fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, output_port) << ";" << std::endl; - } - - /* Add an empty line as splitter */ - fp << std::endl; - - /* Condition ends for the benchmark instanciation */ - print_verilog_endif(fp); - - /* Add an empty line as splitter */ - fp << std::endl; + print_verilog_testbench_shared_ports(fp, L_logical_blocks, + std::string(BENCHMARK_PORT_POSTFIX), + std::string(FPGA_PORT_POSTFIX), + std::string(CHECKFLAG_PORT_POSTFIX), + std::string(autochecked_simulation_flag)); /* Instantiate an integer to count the number of error * and determine if the simulation succeed or failed diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c index 19f6bbc50..1f2d6c3b3 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c @@ -90,26 +90,36 @@ void write_include_netlists (char* src_dir_formatted, */ fprintf(fp, "`include \"%s%s\"\n", src_dir_formatted, generate_fpga_top_netlist_name(std::string(verilog_netlist_file_postfix)).c_str()); + fprintf(fp, "\n"); + fprintf(fp, "`ifdef %s\n", verilog_formal_verification_preproc_flag); - fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, + fprintf(fp, "\t`include \"%s%s%s\"\n", src_dir_formatted, chomped_circuit_name, formal_verification_verilog_file_postfix); - fprintf(fp, " `ifdef %s\n", formal_simulation_flag); - fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, + fprintf(fp, "\t`ifdef %s\n", formal_simulation_flag); + fprintf(fp, "\t\t`include \"%s%s%s\"\n", src_dir_formatted, chomped_circuit_name, random_top_testbench_verilog_file_postfix); - fprintf(fp, " `endif\n"); - fprintf(fp, "`elsif %s\n", initial_simulation_flag); + fprintf(fp, " \t`endif\n"); + fprintf(fp, "`endif\n"); + + fprintf(fp, "\n"); + + fprintf(fp, "`ifdef %s\n", autochecked_simulation_flag); + /* TODO: bring these testbench onboard when it is ready fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, chomped_circuit_name, top_testbench_verilog_file_postfix); fprintf(fp, "`elsif %s\n", autochecked_simulation_flag); + */ fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, chomped_circuit_name, autocheck_top_testbench_verilog_file_postfix); - */ fprintf(fp, "`endif\n"); + + fprintf(fp, "\n"); + fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, default_rr_dir_name, routing_verilog_file_name); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp index 7d519d543..ee2a80ea6 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.cpp @@ -461,3 +461,104 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp, fp << std::endl; } +/******************************************************************** + * Print Verilog declaration of shared ports appear in testbenches + * which are + * 1. the shared input ports (registers) to drive both + * FPGA fabric and benchmark instance + * 2. the output ports (wires) for both FPGA fabric and benchmark instance + * 3. the checking flag ports to evaluate if outputs matches under the + * same input vectors + *******************************************************************/ +void print_verilog_testbench_shared_ports(std::fstream& fp, + const std::vector& L_logical_blocks, + const std::string& benchmark_output_port_postfix, + const std::string& fpga_output_port_postfix, + const std::string& check_flag_port_postfix, + const std::string& autocheck_preprocessing_flag) { + /* Validate the file stream */ + check_file_handler(fp); + + + /* Instantiate register for inputs stimulis */ + print_verilog_comment(fp, std::string("----- Shared inputs -------")); + for (const t_logical_block& lb : L_logical_blocks) { + /* We care only those logic blocks which are input I/Os */ + if (VPACK_INPAD != lb.type) { + continue; + } + + /* Skip clocks because they are handled in another function */ + if (TRUE == lb.is_clock) { + continue; + } + + /* Each logical block assumes a single-width port */ + BasicPort input_port(std::string(lb.name), 1); + fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, input_port) << ";" << std::endl; + } + + /* Add an empty line as splitter */ + fp << std::endl; + + /* Instantiate wires for FPGA fabric outputs */ + print_verilog_comment(fp, std::string("----- FPGA fabric outputs -------")); + + for (const t_logical_block& lb : L_logical_blocks) { + /* We care only those logic blocks which are input I/Os */ + if (VPACK_OUTPAD != lb.type) { + continue; + } + + /* Each logical block assumes a single-width port */ + BasicPort output_port(std::string(std::string(lb.name) + fpga_output_port_postfix), 1); + fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, output_port) << ";" << std::endl; + } + + /* Add an empty line as splitter */ + fp << std::endl; + + /* Benchmark is instanciated conditionally: only when a preprocessing flag is enable */ + print_verilog_preprocessing_flag(fp, std::string(autocheck_preprocessing_flag)); + + /* Add an empty line as splitter */ + fp << std::endl; + + /* Instantiate wire for benchmark output */ + print_verilog_comment(fp, std::string("----- Benchmark outputs -------")); + for (const t_logical_block& lb : L_logical_blocks) { + /* We care only those logic blocks which are input I/Os */ + if (VPACK_OUTPAD != lb.type) { + continue; + } + + /* Each logical block assumes a single-width port */ + BasicPort output_port(std::string(std::string(lb.name) + benchmark_output_port_postfix), 1); + fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, output_port) << ";" << std::endl; + } + + /* Add an empty line as splitter */ + fp << std::endl; + + /* Instantiate register for output comparison */ + print_verilog_comment(fp, std::string("----- Output vectors checking flags -------")); + for (const t_logical_block& lb : L_logical_blocks) { + /* We care only those logic blocks which are input I/Os */ + if (VPACK_OUTPAD != lb.type) { + continue; + } + + /* Each logical block assumes a single-width port */ + BasicPort output_port(std::string(std::string(lb.name) + check_flag_port_postfix), 1); + fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, output_port) << ";" << std::endl; + } + + /* Add an empty line as splitter */ + fp << std::endl; + + /* Condition ends for the benchmark instanciation */ + print_verilog_endif(fp); + + /* Add an empty line as splitter */ + fp << std::endl; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h index 3c67f6eaa..0bbb1bc53 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_testbench_utils.h @@ -64,4 +64,11 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp, const std::string& check_flag_port_postfix, const BasicPort& clock_port); +void print_verilog_testbench_shared_ports(std::fstream& fp, + const std::vector& L_logical_blocks, + const std::string& benchmark_output_port_postfix, + const std::string& fpga_output_port_postfix, + const std::string& check_flag_port_postfix, + const std::string& autocheck_preprocessing_flag); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp index f10aecc3d..e5c89dd8f 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp @@ -288,6 +288,7 @@ static void print_verilog_top_testbench_ports(std::fstream& fp, const ModuleManager& module_manager, const ModuleId& top_module, + const std::vector& L_logical_blocks, const e_sram_orgz& sram_orgz_type, const std::string& circuit_name){ /* Validate the file stream */ @@ -295,7 +296,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp, /* Print module definition */ fp << "module " << circuit_name << std::string(modelsim_autocheck_testbench_module_postfix); - fp << " (" << std::endl; + fp << ";" << std::endl; /* Print regular local wires: * 1. global ports, i.e., reset, set and clock signals @@ -304,7 +305,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp, /* Global ports of top-level module */ print_verilog_comment(fp, std::string("----- Local wires for global ports of FPGA fabric -----")); for (const BasicPort& module_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GLOBAL_PORT)) { - fp << generate_verilog_port(VERILOG_PORT_REG, module_port) << ";" << std::endl; + fp << generate_verilog_port(VERILOG_PORT_WIRE, module_port) << ";" << std::endl; } /* Add an empty line as a splitter */ fp << std::endl; @@ -312,7 +313,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp, /* Datapath I/Os of top-level module */ print_verilog_comment(fp, std::string("----- Local wires for I/Os of FPGA fabric -----")); for (const BasicPort& module_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)) { - fp << generate_verilog_port(VERILOG_PORT_REG, module_port) << ";" << std::endl; + fp << generate_verilog_port(VERILOG_PORT_WIRE, module_port) << ";" << std::endl; } /* Add an empty line as a splitter */ fp << std::endl; @@ -352,6 +353,12 @@ void print_verilog_top_testbench_ports(std::fstream& fp, /* Configuration ports depend on the organization of SRAMs */ print_verilog_top_testbench_config_protocol_port(fp, sram_orgz_type); + print_verilog_testbench_shared_ports(fp, L_logical_blocks, + std::string(TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX), + std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX), + std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX), + std::string(autochecked_simulation_flag)); + /* Instantiate an integer to count the number of error and * determine if the simulation succeed or failed */ @@ -625,8 +632,10 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp, fp << "initial" << std::endl; fp << "\tbegin" << std::endl; print_verilog_comment(fp, "----- Configuration chain default input -----"); - fp << "\t"; - print_verilog_wire_constant_values(fp, config_chain_head_port, initial_values); + fp << "\t\t"; + fp << generate_verilog_port_constant_values(config_chain_head_port, initial_values); + fp << ";"; + fp << std::endl; /* Attention: the configuration chain protcol requires the last configuration bit is fed first @@ -718,7 +727,6 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, const std::string& circuit_name, const std::string& verilog_fname, const std::string& verilog_dir, - const std::string& reference_benchmark_file, const t_spice_params& simulation_parameters) { vpr_printf(TIO_MESSAGE_INFO, "Writing Autocheck Testbench for FPGA Top-level Verilog netlist for %s...", @@ -741,16 +749,13 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, /* Print preprocessing flags and external netlists */ print_verilog_include_defines_preproc_file(fp, verilog_dir); - /* Include reference benchmark file */ - print_verilog_include_netlist(fp, reference_benchmark_file); - /* Find the top_module */ ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name()); VTR_ASSERT(true == module_manager.valid_module_id(top_module)); /* Start of testbench */ //dump_verilog_top_auto_testbench_ports(fp, cur_sram_orgz_info, circuit_name, fpga_verilog_opts); - print_verilog_top_testbench_ports(fp, module_manager, top_module, + print_verilog_top_testbench_ports(fp, module_manager, top_module, L_logical_blocks, sram_orgz_type, circuit_name); /* Find the clock period */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.h index c570b6293..ab4a7f955 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.h @@ -20,7 +20,6 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, const std::string& circuit_name, const std::string& verilog_fname, const std::string& verilog_dir, - const std::string& reference_benchmark_file, const t_spice_params& simulation_parameters); void dump_verilog_top_testbench_global_ports(FILE* fp, t_llist* head, From 5d507ae8ee87b1e144c937bb56bd6a0150313126 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 4 Nov 2019 18:05:50 -0700 Subject: [PATCH 24/68] bug fixing in memory module generation; some work should be done to merge nets and uniquifying nets!!! --- .../fpga_x2p/base/module_manager_utils.cpp | 29 +++++++ .../SRC/fpga_x2p/base/module_manager_utils.h | 3 + .../module_builder/build_memory_modules.cpp | 62 +++++++++++---- .../verilog/verilog_include_netlists.c | 2 +- .../verilog/verilog_module_writer.cpp | 76 +++++++++++++++++++ .../verilog/verilog_top_testbench.cpp | 2 +- 6 files changed, 159 insertions(+), 15 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp index 7fe3bf2df..cabd6ba00 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp @@ -304,6 +304,35 @@ bool module_net_is_local_wire(const ModuleManager& module_manager, return true; } +/******************************************************************** + * Identify if a net is an output short connection inside a module: + * The short connection is defined as the direct connection + * between two outputs port of the module + * + * module + * +-----------------------------+ + * | + * src------>+--------------->|--->outputA + * | | + * | | + * +--------------->|--->outputB + * +-----------------------------+ + + *******************************************************************/ +bool module_net_include_output_short_connection(const ModuleManager& module_manager, + const ModuleId& module_id, const ModuleNetId& module_net) { + /* Check all the sink modules of the net */ + size_t contain_num_module_output = 0; + for (ModuleId sink_module : module_manager.net_sink_modules(module_id, module_net)) { + if (module_id == sink_module) { + contain_num_module_output++; + } + } + + /* If we have found more than 1 module outputs, it indicated output short connection! */ + return (1 < contain_num_module_output); +} + /******************************************************************** * Identify if a net is a local short connection inside a module: * The short connection is defined as the direct connection diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h index 5156e7af2..a44abbfc4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h @@ -50,6 +50,9 @@ void add_pb_type_ports_to_module_manager(ModuleManager& module_manager, bool module_net_is_local_wire(const ModuleManager& module_manager, const ModuleId& module_id, const ModuleNetId& module_net); +bool module_net_include_output_short_connection(const ModuleManager& module_manager, + const ModuleId& module_id, const ModuleNetId& module_net); + bool module_net_include_local_short_connection(const ModuleManager& module_manager, const ModuleId& module_id, const ModuleNetId& module_net); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp index 02dca4351..718b47cdb 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp @@ -106,16 +106,20 @@ void add_module_output_nets_to_mem_modules(ModuleManager& module_manager, * j-th pin of output port of the i-th child module is wired to the j + i*W -th * pin of output port of the memory module, where W is the size of port * 3. It assumes fixed port name for output ports + * + * We cache the module nets that have been created because they will be used later ********************************************************************/ static -void add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager, - const ModuleId& mem_module, - const std::string& mem_module_output_name, - const CircuitLibrary& circuit_lib, - const CircuitPortId& circuit_port, - const ModuleId& child_module, - const size_t& child_index, - const size_t& child_instance) { +std::vector add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager, + const ModuleId& mem_module, + const std::string& mem_module_output_name, + const CircuitLibrary& circuit_lib, + const CircuitPortId& circuit_port, + const ModuleId& child_module, + const size_t& child_index, + const size_t& child_instance) { + std::vector module_nets; + /* Wire inputs of parent module to inputs of child modules */ ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_lib_name(circuit_port)); ModulePortId sink_port_id = module_manager.find_module_port(mem_module, mem_module_output_name); @@ -128,7 +132,12 @@ void add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager, /* Sink node of the input net is the input of sram module */ size_t sink_pin_id = child_index * circuit_lib.port_size(circuit_port) + module_manager.module_port(mem_module, sink_port_id).pins()[pin_id]; module_manager.add_module_net_sink(mem_module, net, mem_module, 0, sink_port_id, sink_pin_id); + + /* Cache the nets */ + module_nets.push_back(net); } + + return module_nets; } /******************************************************************** @@ -155,9 +164,13 @@ void add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager, static void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager, const ModuleId& parent_module, + const std::vector& output_nets, const CircuitLibrary& circuit_lib, const CircuitPortId& model_input_port, const CircuitPortId& model_output_port) { + /* Counter for the nets */ + size_t net_counter = 0; + for (size_t mem_index = 0; mem_index < module_manager.configurable_children(parent_module).size(); ++mem_index) { ModuleId net_src_module_id; size_t net_src_instance_id; @@ -203,11 +216,21 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager, /* Create a net for each pin */ for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { /* Create a net and add source and sink to it */ - ModuleNetId net = module_manager.create_module_net(parent_module); + ModuleNetId net; + if (0 == mem_index) { + net = module_manager.create_module_net(parent_module); + } else { + net = output_nets[net_counter]; + } /* Add net source */ module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); /* Add net sink */ module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); + + /* Update net counter */ + if (0 < mem_index) { + net_counter++; + } } } @@ -237,12 +260,17 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager, /* Create a net for each pin */ for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { /* Create a net and add source and sink to it */ - ModuleNetId net = module_manager.create_module_net(parent_module); + ModuleNetId net = output_nets[net_counter]; /* Add net source */ module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); /* Add net sink */ module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); + + /* Update net counter */ + net_counter++; } + + VTR_ASSERT(net_counter == output_nets.size()); } /********************************************************************* @@ -381,6 +409,9 @@ void build_memory_chain_module(ModuleManager& module_manager, /* Find the sram module in the module manager */ ModuleId sram_mem_module = module_manager.find_module(circuit_lib.model_name(sram_model)); + /* Cache the output nets for non-inverted data output */ + std::vector mem_output_nets; + /* Instanciate each submodule */ for (size_t i = 0; i < num_mems; ++i) { size_t sram_mem_instance = module_manager.num_instance(mem_module, sram_mem_module); @@ -396,13 +427,18 @@ void build_memory_chain_module(ModuleManager& module_manager, VTR_ASSERT( 1 == iport); port_name = generate_configuration_chain_inverted_data_out_name(); } - add_module_output_nets_to_chain_mem_modules(module_manager, mem_module, port_name, circuit_lib, sram_output_ports[iport], - sram_mem_module, i, sram_mem_instance); + std::vector output_nets = add_module_output_nets_to_chain_mem_modules(module_manager, mem_module, + port_name, circuit_lib, sram_output_ports[iport], + sram_mem_module, i, sram_mem_instance); + /* Cache only for regular data outputs */ + if (0 == iport) { + mem_output_nets.insert(mem_output_nets.end(), output_nets.begin(), output_nets.end()); + } } } /* Build module nets to wire the configuration chain */ - add_module_nets_to_cmos_memory_chain_module(module_manager, mem_module, + add_module_nets_to_cmos_memory_chain_module(module_manager, mem_module, mem_output_nets, circuit_lib, sram_input_ports[0], sram_output_ports[0]); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c index 1f2d6c3b3..642ac9310 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c @@ -113,7 +113,7 @@ void write_include_netlists (char* src_dir_formatted, top_testbench_verilog_file_postfix); fprintf(fp, "`elsif %s\n", autochecked_simulation_flag); */ - fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, + fprintf(fp, "\t`include \"%s%s%s\"\n", src_dir_formatted, chomped_circuit_name, autocheck_top_testbench_verilog_file_postfix); fprintf(fp, "`endif\n"); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_module_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_module_writer.cpp index 2a495e91a..3a4bebcf8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_module_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_module_writer.cpp @@ -169,6 +169,50 @@ std::vector find_verilog_module_local_wires(const ModuleManager& modu return local_wires; } +/******************************************************************** + * Print a Verilog wire connection + * We search all the sinks of the net, + * if we find a module output, we try to find the next module output + * among the sinks of the net + * For each module output (except the first one), we print a wire connection + *******************************************************************/ +static +void print_verilog_module_output_short_connection(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& module_id, + const ModuleNetId& module_net) { + /* Ensure a valid file stream */ + check_file_handler(fp); + + bool first_port = true; + BasicPort src_port; + + /* We have found a module input, now check all the sink modules of the net */ + for (ModuleNetSinkId net_sink : module_manager.module_net_sinks(module_id, module_net)) { + ModuleId sink_module = module_manager.net_sink_modules(module_id, module_net)[net_sink]; + if (module_id != sink_module) { + continue; + } + + /* Find the sink port and pin information */ + ModulePortId sink_port_id = module_manager.net_sink_ports(module_id, module_net)[net_sink]; + size_t sink_pin = module_manager.net_sink_pins(module_id, module_net)[net_sink]; + BasicPort sink_port(module_manager.module_port(module_id, sink_port_id).get_name(), sink_pin, sink_pin); + + /* For the first module output, this is the source port, we do nothing and go to the next */ + if (true == first_port) { + src_port = sink_port; + /* Flip the flag */ + first_port = false; + continue; + } + + /* We need to print a wire connection here */ + print_verilog_wire_connection(fp, sink_port, src_port, false); + } +} + + /******************************************************************** * Print a Verilog wire connection * We search all the sources of the net, @@ -242,6 +286,36 @@ void print_verilog_module_local_short_connections(std::fstream& fp, } } +/******************************************************************** + * Print output short connections inside a Verilog module + * The output short connection is defined as the direct connection + * between two output ports of the module + * This type of connection is not covered when printing Verilog instances + * Therefore, they are covered in this function + * + * module + * +-----------------------------+ + * | + * src------>+--------------->|--->outputA + * | | + * | | + * +--------------->|--->outputB + * +-----------------------------+ + *******************************************************************/ +static +void print_verilog_module_output_short_connections(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& module_id) { + /* Local wires come from the child modules */ + for (ModuleNetId module_net : module_manager.module_nets(module_id)) { + /* We only care the nets that indicate short connections */ + if (false == module_net_include_output_short_connection(module_manager, module_id, module_net)) { + continue; + } + print_verilog_module_output_short_connection(fp, module_manager, module_id, module_net); + } +} + /******************************************************************** * Write a Verilog instance to a file * This function will name the input and output connections to @@ -372,6 +446,8 @@ void write_verilog_module_to_file(std::fstream& fp, /* Print local connection (from module inputs to output! */ print_verilog_module_local_short_connections(fp, module_manager, module_id); + + print_verilog_module_output_short_connections(fp, module_manager, module_id); /* Print an empty line as splitter */ fp << std::endl; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp index e5c89dd8f..644df5246 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp @@ -547,7 +547,7 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp, print_verilog_comment(fp, std::string("----- Actual operating clock is triggered only when " + config_done_port.get_name() + " is enabled -----")); fp << "\tassign " << generate_verilog_port(VERILOG_PORT_CONKT, op_clock_port); fp << " = " << generate_verilog_port(VERILOG_PORT_CONKT, op_clock_register_port); - fp << " & (~" << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port) << ")"; + fp << " & " << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port); fp << ";" << std::endl; fp << std::endl; From ebab0e91ef7c0e058f2d6fc5a8afa1921035f524 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 4 Nov 2019 20:55:30 -0700 Subject: [PATCH 25/68] refactored include netlist writer --- .../libarchfpga/SRC/circuit_library_utils.cpp | 23 ++++ .../libarchfpga/SRC/circuit_library_utils.h | 2 + .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 9 ++ .../verilog_formal_random_top_testbench.cpp | 2 - .../verilog/verilog_include_netlists.cpp | 106 ++++++++++++++++++ .../verilog/verilog_include_netlists.h | 8 ++ .../fpga_x2p/verilog/verilog_writer_utils.cpp | 2 - 7 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.cpp diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp b/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp index cb7641b0a..7c3a24d94 100644 --- a/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp @@ -240,3 +240,26 @@ std::vector find_circuit_library_global_ports(const CircuitLibrar return global_ports; } + +/******************************************************************** + * A generic function to find all the unique user-defined + * Verilog netlists in a circuit library + * Netlists with same names will be considered as one + *******************************************************************/ +std::vector find_circuit_library_unique_verilog_netlists(const CircuitLibrary& circuit_lib) { + std::vector netlists; + + for (const CircuitModelId& model : circuit_lib.models()) { + /* Skip empty netlist names */ + if (true == circuit_lib.model_verilog_netlist(model).empty()) { + continue; + } + /* See if the netlist name is already in the list */ + std::vector::iterator it = std::find(netlists.begin(), netlists.end(), circuit_lib.model_verilog_netlist(model)); + if (it == netlists.end()) { + netlists.push_back(circuit_lib.model_verilog_netlist(model)); + } + } + + return netlists; +} diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.h b/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.h index c0c8251c7..056777c61 100644 --- a/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.h +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.h @@ -29,4 +29,6 @@ size_t find_circuit_num_config_bits(const CircuitLibrary& circuit_lib, std::vector find_circuit_library_global_ports(const CircuitLibrary& circuit_lib); +std::vector find_circuit_library_unique_verilog_netlists(const CircuitLibrary& circuit_lib); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index eb6eadcca..6716cb1e4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -505,9 +505,18 @@ void vpr_fpga_verilog(ModuleManager& module_manager, sram_verilog_orgz_info->type); } + /* TODO: this is an old function, to be shadowed */ + /* write_include_netlists(src_dir_path, chomped_circuit_name, *(Arch.spice) ); + */ + + /* TODO: new function: to be tested */ + print_include_netlists(std::string(src_dir_path), + std::string(chomped_circuit_name), + std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file), + Arch.spice->circuit_lib); vpr_printf(TIO_MESSAGE_INFO, "Outputted %lu Verilog modules in total.\n", module_manager.num_modules()); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp index 26b86d7a1..b52d41d43 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_formal_random_top_testbench.cpp @@ -204,8 +204,6 @@ void print_verilog_random_top_testbench(const std::string& circuit_name, print_verilog_include_netlist(fp, std::string(verilog_dir + std::string(defines_verilog_simulation_file_name))); - print_verilog_include_netlist(fp, std::string(fpga_verilog_opts.reference_verilog_benchmark_file)); - /* Preparation: find all the clock ports */ std::vector clock_port_names = find_benchmark_clock_port_name(L_logical_blocks); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.cpp new file mode 100644 index 000000000..814c97705 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.cpp @@ -0,0 +1,106 @@ +/******************************************************************** + * This file includes functions that are used to generate Verilog files + * or code blocks, with a focus on + * `include user-defined or auto-generated netlists in Verilog format + *******************************************************************/ +#include + +#include "vtr_assert.h" + +#include "circuit_library_utils.h" + +#include "fpga_x2p_utils.h" +#include "fpga_x2p_naming.h" + +#include "verilog_writer_utils.h" +#include "verilog_include_netlists.h" + +/******************************************************************** + * Local constant variables + *******************************************************************/ +constexpr char* TOP_INCLUDE_NETLIST_FILE_NAME_POSTFIX = "_include_netlists.v"; + +/******************************************************************** + * Print a file that includes all the netlists that have been generated + * and user-defined. + * Some netlists are open to compile under specific preprocessing flags + *******************************************************************/ +void print_include_netlists(const std::string& src_dir, + const std::string& circuit_name, + const std::string& reference_benchmark_file, + const CircuitLibrary& circuit_lib) { + std::string verilog_fname = src_dir + circuit_name + std::string(TOP_INCLUDE_NETLIST_FILE_NAME_POSTFIX); + + /* Create the file stream */ + std::fstream fp; + fp.open(verilog_fname, std::fstream::out | std::fstream::trunc); + + /* Validate the file stream */ + check_file_handler(fp); + + /* Print the title */ + print_verilog_file_header(fp, std::string("Netlist Summary")); + + /* Print preprocessing flags */ + print_verilog_comment(fp, std::string("------ Include defines: preproc flags -----")); + print_verilog_include_netlist(fp, std::string(src_dir + std::string(defines_verilog_file_name))); + fp << std::endl; + + print_verilog_comment(fp, std::string("------ Include simulation defines -----")); + print_verilog_include_netlist(fp, src_dir + std::string(defines_verilog_simulation_file_name)); + fp << std::endl; + + /* Include all the user-defined netlists */ + for (const std::string& user_defined_netlist : find_circuit_library_unique_verilog_netlists(circuit_lib)) { + print_verilog_include_netlist(fp, user_defined_netlist); + } + + /* Include all the primitive modules */ + print_verilog_include_netlist(fp, src_dir + std::string(default_submodule_dir_name) + std::string(submodule_verilog_file_name)); + fp << std::endl; + + /* Include all the CLB, heterogeneous block modules */ + print_verilog_include_netlist(fp, src_dir + std::string(default_lb_dir_name) + std::string(logic_block_verilog_file_name)); + fp << std::endl; + + /* Include all the routing architecture modules */ + print_verilog_include_netlist(fp, src_dir + std::string(default_rr_dir_name) + std::string(routing_verilog_file_name)); + fp << std::endl; + + /* Include FPGA top module */ + print_verilog_include_netlist(fp, src_dir + generate_fpga_top_netlist_name(std::string(verilog_netlist_file_postfix))); + fp << std::endl; + + /* Include reference benchmark netlist only when auto-check flag is enabled */ + print_verilog_preprocessing_flag(fp, std::string(autochecked_simulation_flag)); + fp << "\t"; + print_verilog_include_netlist(fp, std::string(reference_benchmark_file)); + print_verilog_endif(fp); + fp << std::endl; + + /* Include formal verification netlists only when formal verification flag is enable */ + print_verilog_preprocessing_flag(fp, std::string(verilog_formal_verification_preproc_flag)); + fp << "\t"; + print_verilog_include_netlist(fp, src_dir + circuit_name + std::string(formal_verification_verilog_file_postfix)); + + /* Include formal verification testbench only when formal simulation flag is enabled */ + fp << "\t"; + print_verilog_preprocessing_flag(fp, std::string(formal_simulation_flag)); + fp << "\t\t"; + print_verilog_include_netlist(fp, src_dir + circuit_name + std::string(random_top_testbench_verilog_file_postfix)); + fp << "\t"; + print_verilog_endif(fp); + + print_verilog_endif(fp); + fp << std::endl; + + /* Include top-level testbench only when auto-check flag is enabled */ + print_verilog_preprocessing_flag(fp, std::string(autochecked_simulation_flag)); + fp << "\t"; + print_verilog_include_netlist(fp, src_dir + circuit_name + std::string(autocheck_top_testbench_verilog_file_postfix)); + print_verilog_endif(fp); + fp << std::endl; + + /* Close the file stream */ + fp.close(); +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h index 85659c56a..e0a92a2de 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h @@ -1,6 +1,14 @@ #ifndef VERILOG_INCLUDE_NETLISTS_H #define VERILOG_INCLUDE_NETLISTS_H +#include +#include "circuit_library.h" + +void print_include_netlists(const std::string& src_dir, + const std::string& circuit_name, + const std::string& reference_benchmark_file, + const CircuitLibrary& circuit_lib); + void write_include_netlists (char* src_dir_formatted, char* chomped_circuit_name, t_spice spice); 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 20f7c6dd0..e210a68e0 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 @@ -52,9 +52,7 @@ void print_verilog_include_netlist(std::fstream& fp, const std::string& netlist_name) { check_file_handler(fp); - fp << "//------ Include external netlist: " << netlist_name << " -----" << std::endl; fp << "`include \"" << netlist_name << "\"" << std::endl; - fp << "//------ End include external netlist: " << netlist_name << " -----" << std::endl; } /************************************************ From aaaf7a0d19f3ee6e409068928ad89042a8f533aa Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 4 Nov 2019 21:06:14 -0700 Subject: [PATCH 26/68] remove legacy codes in writing include netlists --- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 9 +- .../verilog/verilog_include_netlists.c | 141 ------------------ .../verilog/verilog_include_netlists.h | 4 - 3 files changed, 1 insertion(+), 153 deletions(-) delete mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 6716cb1e4..a8f9c5020 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -505,14 +505,7 @@ void vpr_fpga_verilog(ModuleManager& module_manager, sram_verilog_orgz_info->type); } - /* TODO: this is an old function, to be shadowed */ - /* - write_include_netlists(src_dir_path, - chomped_circuit_name, - *(Arch.spice) ); - */ - - /* TODO: new function: to be tested */ + /* Print a Verilog file including all the netlists that have been generated */ print_include_netlists(std::string(src_dir_path), std::string(chomped_circuit_name), std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file), diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c deleted file mode 100644 index 642ac9310..000000000 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.c +++ /dev/null @@ -1,141 +0,0 @@ -// Formality runsim -// Need to declare formality_script_name_postfix = "formality_script.tcl"; -#include -#include -#include -#include -#include -#include -#include -#include - -/* Include vpr structs*/ -#include "util.h" -#include "physical_types.h" -#include "vpr_types.h" -#include "globals.h" -#include "rr_graph.h" -#include "vpr_utils.h" -#include "path_delay.h" -#include "stats.h" - -/* Include FPGA-SPICE utils */ -#include "linkedlist.h" -#include "fpga_x2p_utils.h" -#include "fpga_x2p_globals.h" -#include "fpga_x2p_naming.h" - -/* Include verilog utils */ -#include "verilog_global.h" -#include "verilog_utils.h" - -#include "verilog_include_netlists.h" - -static -void include_netlists_include_user_defined_verilog_netlists(FILE* fp, - t_spice spice) { - int i; - - /* A valid file handler*/ - if (NULL == fp) { - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d])Invalid File Handler!\n", - __FILE__, __LINE__); - exit(1); - } - - /* Include user-defined sub-circuit netlist */ - for (i = 0; i < spice.num_include_netlist; i++) { - if (0 == spice.include_netlists[i].included) { - assert(NULL != spice.include_netlists[i].path); - fprintf(fp, "`include \"%s\"\n", spice.include_netlists[i].path); - spice.include_netlists[i].included = 1; - } else { - assert(1 == spice.include_netlists[i].included); - } - } - - return; -} - -void write_include_netlists (char* src_dir_formatted, - char* chomped_circuit_name, - t_spice spice){ - - char* include_netlists_file_name = NULL; -/* int output_length; */ -/* int pos; */ - FILE* fp = NULL; - - include_netlists_file_name = my_strcat(src_dir_formatted, my_strcat(chomped_circuit_name, "_include_netlists.v")); - fp = fopen(include_netlists_file_name, "w"); - if (NULL == fp) { - vpr_printf(TIO_MESSAGE_ERROR, - "(FILE:%s,LINE[%d])Failure in create formality script %s", - __FILE__, __LINE__, include_netlists_file_name); - exit(1); - } - - /* Print the title */ - dump_verilog_file_header(fp, "Netlists Summary"); - - /* Print preprocessing flags */ - verilog_include_defines_preproc_file(fp, src_dir_formatted); - verilog_include_simulation_defines_file(fp, src_dir_formatted); - - /* - fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, - chomped_circuit_name, - verilog_top_postfix); - */ - fprintf(fp, "`include \"%s%s\"\n", src_dir_formatted, - generate_fpga_top_netlist_name(std::string(verilog_netlist_file_postfix)).c_str()); - fprintf(fp, "\n"); - - fprintf(fp, "`ifdef %s\n", verilog_formal_verification_preproc_flag); - fprintf(fp, "\t`include \"%s%s%s\"\n", src_dir_formatted, - chomped_circuit_name, - formal_verification_verilog_file_postfix); - fprintf(fp, "\t`ifdef %s\n", formal_simulation_flag); - fprintf(fp, "\t\t`include \"%s%s%s\"\n", src_dir_formatted, - chomped_circuit_name, - random_top_testbench_verilog_file_postfix); - fprintf(fp, " \t`endif\n"); - fprintf(fp, "`endif\n"); - - fprintf(fp, "\n"); - - fprintf(fp, "`ifdef %s\n", autochecked_simulation_flag); - - /* TODO: bring these testbench onboard when it is ready - fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, - chomped_circuit_name, - top_testbench_verilog_file_postfix); - fprintf(fp, "`elsif %s\n", autochecked_simulation_flag); - */ - fprintf(fp, "\t`include \"%s%s%s\"\n", src_dir_formatted, - chomped_circuit_name, - autocheck_top_testbench_verilog_file_postfix); - fprintf(fp, "`endif\n"); - - fprintf(fp, "\n"); - - fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, - default_rr_dir_name, - routing_verilog_file_name); - fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, - default_lb_dir_name, - logic_block_verilog_file_name); - fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, - default_submodule_dir_name, - submodule_verilog_file_name); - fprintf(fp, "`include \"%s%s%s\"\n", src_dir_formatted, - default_submodule_dir_name, - config_peripheral_verilog_file_name); - init_include_user_defined_verilog_netlists(spice); - include_netlists_include_user_defined_verilog_netlists(fp, spice); - - fclose(fp); - - return; -} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h index e0a92a2de..6b43a44d5 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h @@ -9,8 +9,4 @@ void print_include_netlists(const std::string& src_dir, const std::string& reference_benchmark_file, const CircuitLibrary& circuit_lib); -void write_include_netlists (char* src_dir_formatted, - char* chomped_circuit_name, - t_spice spice); - #endif From 8ef9e994d80e5ffe6b439a9b6c1f5d42a2d67fd0 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 12:18:23 -0700 Subject: [PATCH 27/68] rename source files to be what they are actually doing --- vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c | 2 +- ...og_include_netlists.cpp => verilog_auxiliary_netlists.cpp} | 2 +- ...erilog_include_netlists.h => verilog_auxiliary_netlists.h} | 4 ++-- vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename vpr7_x2p/vpr/SRC/fpga_x2p/verilog/{verilog_include_netlists.cpp => verilog_auxiliary_netlists.cpp} (99%) rename vpr7_x2p/vpr/SRC/fpga_x2p/verilog/{verilog_include_netlists.h => verilog_auxiliary_netlists.h} (80%) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index a8f9c5020..4df691a77 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -61,7 +61,7 @@ #include "verilog_sdc.h" #include "verilog_formality_autodeck.h" #include "verilog_sdc_pb_types.h" -#include "verilog_include_netlists.h" +#include "verilog_auxiliary_netlists.h" #include "simulation_info_writer.h" #include "verilog_api.h" diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp similarity index 99% rename from vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.cpp rename to vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp index 814c97705..4e2597fdf 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp @@ -13,7 +13,7 @@ #include "fpga_x2p_naming.h" #include "verilog_writer_utils.h" -#include "verilog_include_netlists.h" +#include "verilog_auxiliary_netlists.h" /******************************************************************** * Local constant variables diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h similarity index 80% rename from vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h rename to vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h index 6b43a44d5..fca4b1c26 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_include_netlists.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h @@ -1,5 +1,5 @@ -#ifndef VERILOG_INCLUDE_NETLISTS_H -#define VERILOG_INCLUDE_NETLISTS_H +#ifndef VERILOG_AUXILIARY_NETLISTS_H +#define VERILOG_AUXILIARY_NETLISTS_H #include #include "circuit_library.h" diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c index 0bdad0ee8..47b5fa027 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c @@ -283,7 +283,7 @@ void dump_verilog_defines_preproc(char* subckt_dir, if (NULL == fp) { vpr_printf(TIO_MESSAGE_ERROR, - "(FILE:%s,LINE[%d])Failure in create Verilog netlist %s", + "(FILE:%s,LINE[%d]) Failure in create Verilog netlist %s", __FILE__, __LINE__, fname); exit(1); } From 13f2d33d37462fa0df41879f8eef1a1db804deeb Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 12:41:43 -0700 Subject: [PATCH 28/68] refactored fpga_define.v generation Please enter the commit message for your changes. Lines starting --- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 6 +++ .../verilog/verilog_auxiliary_netlists.cpp | 49 +++++++++++++++++++ .../verilog/verilog_auxiliary_netlists.h | 4 ++ .../fpga_x2p/verilog/verilog_writer_utils.cpp | 11 +++++ .../fpga_x2p/verilog/verilog_writer_utils.h | 4 ++ 5 files changed, 74 insertions(+) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 4df691a77..5df87ef8c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -264,8 +264,14 @@ void vpr_fpga_verilog(ModuleManager& module_manager, init_pb_types_num_iopads(); /* init_grids_num_mode_bits(); */ + /* TODO: This is the old function, which will be deprecated when refactoring is done */ + /* dump_verilog_defines_preproc(src_dir_path, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts); + */ + + print_verilog_preprocessing_flags_netlist(std::string(src_dir_path), + vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts); dump_verilog_simulation_preproc(src_dir_path, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp index 4e2597fdf..4607e1b16 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp @@ -12,6 +12,7 @@ #include "fpga_x2p_utils.h" #include "fpga_x2p_naming.h" +#include "verilog_global.h" #include "verilog_writer_utils.h" #include "verilog_auxiliary_netlists.h" @@ -104,3 +105,51 @@ void print_include_netlists(const std::string& src_dir, /* Close the file stream */ fp.close(); } + +/******************************************************************** + * Print a Verilog file containing preprocessing flags + * which are used enable/disable some features in FPGA Verilog modules + *******************************************************************/ +void print_verilog_preprocessing_flags_netlist(const std::string& src_dir, + const t_syn_verilog_opts& fpga_verilog_opts) { + + std::string verilog_fname = src_dir + std::string(defines_verilog_file_name); + + /* Create the file stream */ + std::fstream fp; + fp.open(verilog_fname, std::fstream::out | std::fstream::trunc); + + /* Validate the file stream */ + check_file_handler(fp); + + /* Print the title */ + print_verilog_file_header(fp, std::string("Preprocessing flags to enable/disable features in FPGA Verilog modules")); + + /* To enable timing */ + if (TRUE == fpga_verilog_opts.include_timing) { + print_verilog_define_flag(fp, std::string(verilog_timing_preproc_flag), 1); + fp << std::endl; + } + + /* To enable timing */ + if (TRUE == fpga_verilog_opts.include_signal_init) { + print_verilog_define_flag(fp, std::string(verilog_signal_init_preproc_flag), 1); + fp << std::endl; + } + + /* To enable formal verfication flag */ + if (TRUE == fpga_verilog_opts.print_formal_verification_top_netlist) { + print_verilog_define_flag(fp, std::string(verilog_formal_verification_preproc_flag), 1); + fp << std::endl; + } + + /* To enable functional verfication with Icarus */ + if (TRUE == fpga_verilog_opts.include_icarus_simulator) { + print_verilog_define_flag(fp, std::string(icarus_simulator_flag), 1); + fp << std::endl; + } + + /* Close the file stream */ + fp.close(); +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h index fca4b1c26..0d0037c3f 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h @@ -3,10 +3,14 @@ #include #include "circuit_library.h" +#include "vpr_types.h" void print_include_netlists(const std::string& src_dir, const std::string& circuit_name, const std::string& reference_benchmark_file, const CircuitLibrary& circuit_lib); +void print_verilog_preprocessing_flags_netlist(const std::string& src_dir, + const t_syn_verilog_opts& fpga_verilog_opts); + #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 e210a68e0..51ddd8107 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 @@ -55,6 +55,17 @@ void print_verilog_include_netlist(std::fstream& fp, fp << "`include \"" << netlist_name << "\"" << std::endl; } +/******************************************************************** + * Print Verilog codes to define a preprocessing flag + *******************************************************************/ +void print_verilog_define_flag(std::fstream& fp, + const std::string& flag_name, + const int& flag_value) { + check_file_handler(fp); + + fp << "`define " << flag_name << " " << flag_value << std::endl; +} + /************************************************ * Generate include files for a Verilog netlist ***********************************************/ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h index a1d57615a..977ae037b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.h @@ -26,6 +26,10 @@ void print_verilog_file_header(std::fstream& fp, void print_verilog_include_netlist(std::fstream& fp, const std::string& netlist_name); +void print_verilog_define_flag(std::fstream& fp, + const std::string& flag_name, + const int& flag_value); + void print_verilog_include_defines_preproc_file(std::fstream& fp, const std::string& verilog_dir); From 66047e4a451c0786f70ed6447f61bd8d19622b2a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 13:45:11 -0700 Subject: [PATCH 29/68] refactoring Verilog simulation flag generations --- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 11 ++- .../verilog/verilog_auxiliary_netlists.cpp | 40 ++++++++++ .../verilog/verilog_auxiliary_netlists.h | 3 + .../vpr/SRC/fpga_x2p/verilog/verilog_utils.c | 74 ------------------- .../vpr/SRC/fpga_x2p/verilog/verilog_utils.h | 3 - 5 files changed, 48 insertions(+), 83 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 5df87ef8c..a92e8b598 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -264,17 +264,16 @@ void vpr_fpga_verilog(ModuleManager& module_manager, init_pb_types_num_iopads(); /* init_grids_num_mode_bits(); */ - /* TODO: This is the old function, which will be deprecated when refactoring is done */ - /* - dump_verilog_defines_preproc(src_dir_path, - vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts); - */ - + /* Print Verilog files containing preprocessing flags */ print_verilog_preprocessing_flags_netlist(std::string(src_dir_path), vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts); + print_verilog_simulation_preprocessing_flags(std::string(src_dir_path), + vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts); + /* dump_verilog_simulation_preproc(src_dir_path, vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts); + */ /* Generate primitive Verilog modules, which are corner stones of FPGA fabric * Note that this function MUST be called before Verilog generation of diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp index 4607e1b16..0aa47d8a6 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.cpp @@ -153,3 +153,43 @@ void print_verilog_preprocessing_flags_netlist(const std::string& src_dir, fp.close(); } +/******************************************************************** + * Print a Verilog file containing simulation-related preprocessing flags + *******************************************************************/ +void print_verilog_simulation_preprocessing_flags(const std::string& src_dir, + const t_syn_verilog_opts& fpga_verilog_opts) { + + std::string verilog_fname = src_dir + std::string(defines_verilog_simulation_file_name); + + /* Create the file stream */ + std::fstream fp; + fp.open(verilog_fname, std::fstream::out | std::fstream::trunc); + + /* Validate the file stream */ + check_file_handler(fp); + + /* Print the title */ + print_verilog_file_header(fp, std::string("Preprocessing flags to enable/disable simulation features")); + + /* To enable manualy checked simulation */ + if (TRUE == fpga_verilog_opts.print_top_testbench) { + print_verilog_define_flag(fp, std::string(initial_simulation_flag), 1); + fp << std::endl; + } + + /* To enable auto-checked simulation */ + if (TRUE == fpga_verilog_opts.print_autocheck_top_testbench) { + print_verilog_define_flag(fp, std::string(autochecked_simulation_flag), 1); + fp << std::endl; + } + + /* To enable pre-configured FPGA simulation */ + if (TRUE == fpga_verilog_opts.print_formal_verification_top_netlist) { + print_verilog_define_flag(fp, std::string(formal_simulation_flag), 1); + fp << std::endl; + } + + + /* Close the file stream */ + fp.close(); +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h index 0d0037c3f..0a56690cd 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_auxiliary_netlists.h @@ -13,4 +13,7 @@ void print_include_netlists(const std::string& src_dir, void print_verilog_preprocessing_flags_netlist(const std::string& src_dir, const t_syn_verilog_opts& fpga_verilog_opts); +void print_verilog_simulation_preprocessing_flags(const std::string& src_dir, + const t_syn_verilog_opts& fpga_verilog_opts); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c index 47b5fa027..319c5447b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c @@ -164,45 +164,6 @@ void dump_verilog_file_header(FILE* fp, return; } -/* Dump preproc */ -void dump_verilog_preproc(FILE* fp, - t_syn_verilog_opts fpga_verilog_opts, - enum e_verilog_tb_type verilog_tb_type) { - - if (NULL == fp) { - vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d]) FileHandle is NULL!\n",__FILE__,__LINE__); - exit(1); - } - - /* To enable timing */ - if (TRUE == fpga_verilog_opts.include_timing) { - fprintf(fp, "`define %s 1\n", verilog_timing_preproc_flag); - fprintf(fp, "\n"); - } - - /* To enable timing */ - if (TRUE == fpga_verilog_opts.include_signal_init) { - fprintf(fp, "`define %s 1\n", verilog_signal_init_preproc_flag); - fprintf(fp, "\n"); - } - - /* To enable formal verfication flag */ - if (TRUE == fpga_verilog_opts.print_formal_verification_top_netlist) { - fprintf(fp, "`define %s 1\n", - verilog_formal_verification_preproc_flag); // the flag to enable formal verification during compilation - fprintf(fp, "\n"); - } - - /* To enable functional verfication with Icarus */ - if (TRUE == fpga_verilog_opts.include_icarus_simulator) { - fprintf(fp, "`define %s 1\n", - icarus_simulator_flag); // the flag to enable formal verification during compilation - fprintf(fp, "\n"); - } - - return; -} - void dump_simulation_preproc(FILE* fp, t_syn_verilog_opts fpga_verilog_opts, enum e_verilog_tb_type verilog_tb_type) { @@ -268,41 +229,6 @@ void dump_verilog_simulation_preproc(char* subckt_dir, return; } -void dump_verilog_defines_preproc(char* subckt_dir, - t_syn_verilog_opts fpga_verilog_opts) { - /* Create a file handler */ - FILE* fp = NULL; - char* file_description = NULL; - char* fname = NULL; - - fname = my_strcat(subckt_dir, - defines_verilog_file_name); - - /* Create a file*/ - fp = fopen(fname, "w"); - - if (NULL == fp) { - vpr_printf(TIO_MESSAGE_ERROR, - "(FILE:%s,LINE[%d]) Failure in create Verilog netlist %s", - __FILE__, __LINE__, fname); - exit(1); - } - - /* Generate the descriptions*/ - file_description = "Preproc Flags"; - dump_verilog_file_header(fp, file_description); - - /* Dump the defines preproc flags*/ - dump_verilog_preproc(fp, fpga_verilog_opts, VERILOG_TB_TOP); - - fclose(fp); - - /* Free */ - my_free(fname); - - return; -} - void verilog_include_defines_preproc_file(FILE* fp, char* verilog_dir) { char* temp_include_file_path = NULL; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h index 1fac4fff5..2e5ec3e9c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h @@ -22,9 +22,6 @@ void dump_simulation_preproc(FILE* fp, void dump_verilog_simulation_preproc(char* subckt_dir, t_syn_verilog_opts fpga_verilog_opts); -void dump_verilog_defines_preproc(char* subckt_dir, - t_syn_verilog_opts fpga_verilog_opts); - void verilog_include_simulation_defines_file(FILE* fp, char* formatted_verilog_dir); From 2fbb88d25b355a48a9d7398eb7e2d3826085b07d Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 13:52:42 -0700 Subject: [PATCH 30/68] remove legacy codes --- .../vpr/SRC/fpga_x2p/verilog/verilog_utils.c | 65 ------------------- .../vpr/SRC/fpga_x2p/verilog/verilog_utils.h | 10 --- 2 files changed, 75 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c index 319c5447b..7fe8eedbe 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.c @@ -164,71 +164,6 @@ void dump_verilog_file_header(FILE* fp, return; } -void dump_simulation_preproc(FILE* fp, - t_syn_verilog_opts fpga_verilog_opts, - enum e_verilog_tb_type verilog_tb_type) { - - if (NULL == fp) { - vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s, LINE[%d]) FileHandle is NULL!\n",__FILE__,__LINE__); - exit(1); - } - - /* To enable manualy checked simulation */ - if (TRUE == fpga_verilog_opts.print_top_testbench) { - fprintf(fp, "`define %s 1\n", initial_simulation_flag); - fprintf(fp, "\n"); - } - - /* To enable auto-checked simulation */ - if (TRUE == fpga_verilog_opts.print_autocheck_top_testbench) { - fprintf(fp, "`define %s 1\n", autochecked_simulation_flag); - fprintf(fp, "\n"); - } - - /* To enable pre-configured FPGA simulation */ - if (TRUE == fpga_verilog_opts.print_formal_verification_top_netlist) { - fprintf(fp, "`define %s 1\n", formal_simulation_flag); - fprintf(fp, "\n"); - } - - return; -} - -void dump_verilog_simulation_preproc(char* subckt_dir, - t_syn_verilog_opts fpga_verilog_opts) { - /* Create a file handler */ - FILE* fp = NULL; - char* file_description = NULL; - char* fname = NULL; - - fname = my_strcat(subckt_dir, - defines_verilog_simulation_file_name); - - /* Create a file*/ - fp = fopen(fname, "w"); - - if (NULL == fp) { - vpr_printf(TIO_MESSAGE_ERROR, - "(FILE:%s,LINE[%d])Failure in create Verilog netlist %s", - __FILE__, __LINE__, fname); - exit(1); - } - - /* Generate the descriptions*/ - file_description = "Simulation Flags"; - dump_verilog_file_header(fp, file_description); - - /* Dump the defines preproc flags*/ - dump_simulation_preproc(fp, fpga_verilog_opts, VERILOG_TB_TOP); - - fclose(fp); - - /* Free */ - my_free(fname); - - return; -} - void verilog_include_defines_preproc_file(FILE* fp, char* verilog_dir) { char* temp_include_file_path = NULL; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h index 2e5ec3e9c..30a4d8863 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_utils.h @@ -15,16 +15,6 @@ void dump_verilog_preproc(FILE* fp, t_syn_verilog_opts fpga_verilog_opts, enum e_verilog_tb_type verilog_tb_type); -void dump_simulation_preproc(FILE* fp, - t_syn_verilog_opts fpga_verilog_opts, - enum e_verilog_tb_type verilog_tb_type); - -void dump_verilog_simulation_preproc(char* subckt_dir, - t_syn_verilog_opts fpga_verilog_opts); - -void verilog_include_simulation_defines_file(FILE* fp, - char* formatted_verilog_dir); - void verilog_include_defines_preproc_file(FILE* fp, char* formatted_verilog_dir); From a308a13d7cb087f9041cdf9db7b411dfe56030d4 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 15:41:59 -0700 Subject: [PATCH 31/68] use prefix instead of lib_name when building modules, then use lib_name for standard cell modules --- openfpga_flow/VerilogNetlists/ff.v | 8 +-- ...m_chain_FC_behavioral_verilog_template.xml | 4 +- .../k6_N10_sram_chain_HC_1IO_template.xml | 4 +- ...m_chain_HC_behavioral_verilog_template.xml | 4 +- ...0_sram_chain_HC_local_encoder_template.xml | 4 +- ...C_non_lut_intermediate_buffer_template.xml | 4 +- .../k6_N10_sram_chain_HC_template.xml | 4 +- ...k6_N10_sram_chain_HC_tileable_template.xml | 4 +- ...k6_N10_sram_chain_HC_tree_mux_template.xml | 4 +- .../libarchfpga/SRC/check_circuit_library.cpp | 12 ++-- .../libarchfpga/SRC/circuit_library_utils.cpp | 2 +- .../vpr/SRC/fpga_x2p/base/module_manager.cpp | 9 +++ .../vpr/SRC/fpga_x2p/base/module_manager.h | 2 + .../fpga_x2p/base/module_manager_utils.cpp | 14 ++--- .../module_builder/build_device_module.cpp | 9 +++ .../build_essential_modules.cpp | 39 ++++++++++++- .../module_builder/build_essential_modules.h | 3 + .../module_builder/build_grid_modules.cpp | 10 ++-- .../module_builder/build_lut_modules.cpp | 36 ++++++------ .../module_builder/build_memory_modules.cpp | 34 +++++------ .../module_builder/build_mux_modules.cpp | 56 +++++++++---------- .../module_builder/build_routing_modules.cpp | 8 +-- .../build_top_module_directs.cpp | 4 +- .../module_builder/build_wire_modules.cpp | 2 +- .../verilog/verilog_essential_gates.cpp | 36 ++++++------ .../vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp | 34 +++++------ .../verilog/verilog_preconfig_top_module.cpp | 2 +- .../SRC/fpga_x2p/verilog/verilog_submodules.c | 2 +- .../verilog/verilog_top_testbench.cpp | 10 ++-- 29 files changed, 212 insertions(+), 152 deletions(-) diff --git a/openfpga_flow/VerilogNetlists/ff.v b/openfpga_flow/VerilogNetlists/ff.v index bd556f936..f0097019e 100644 --- a/openfpga_flow/VerilogNetlists/ff.v +++ b/openfpga_flow/VerilogNetlists/ff.v @@ -76,9 +76,9 @@ endmodule //End Of Module static_dff //----------------------------------------------------- module sc_dff_compact ( /* Global ports go first */ -input pReset, // Reset input +input reset, // Reset input //input set, // set input -input prog_clk, // Clock Input +input clk, // Clock Input /* Local ports follow */ input D, // Data Input output Q, // Q output @@ -88,8 +88,8 @@ output Qb // Q output reg q_reg; //-------------Code Starts Here--------- -always @ ( posedge prog_clk or posedge pReset /*or posedge set*/) -if (pReset) begin +always @ ( posedge clk or posedge reset /*or posedge set*/) +if (reset) begin q_reg <= 1'b0; //end else if (set) begin // q_reg <= 1'b1; diff --git a/openfpga_flow/arch/template/k4_N4_sram_chain_FC_behavioral_verilog_template.xml b/openfpga_flow/arch/template/k4_N4_sram_chain_FC_behavioral_verilog_template.xml index 29badf323..0c932d704 100644 --- a/openfpga_flow/arch/template/k4_N4_sram_chain_FC_behavioral_verilog_template.xml +++ b/openfpga_flow/arch/template/k4_N4_sram_chain_FC_behavioral_verilog_template.xml @@ -321,12 +321,12 @@ - + - + diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml index fa32d4e41..9af75ba69 100644 --- a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml @@ -379,12 +379,12 @@ - + - + diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml index 4d26f30ad..f22464011 100644 --- a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml @@ -379,12 +379,12 @@ - + - + diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml index 48e1503c7..fd4ef33fb 100644 --- a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml @@ -379,12 +379,12 @@ - + - + diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml index ff9d23ac1..7b20e6ff9 100644 --- a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml @@ -377,12 +377,12 @@ - + - + diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml index fa32d4e41..9af75ba69 100644 --- a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml @@ -379,12 +379,12 @@ - + - + diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml index ce1615d0b..4cea2b20c 100644 --- a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml @@ -379,12 +379,12 @@ - + - + diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml index c362da80c..078a876da 100644 --- a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml @@ -379,12 +379,12 @@ - + - + diff --git a/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp b/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp index 5efabf0bc..bf70df367 100644 --- a/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp +++ b/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp @@ -410,7 +410,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) { for (size_t iport = 0; iport < global_ports.size() - 1; ++iport) { for (size_t jport = iport + 1; jport < global_ports.size(); ++jport) { /* Bypass those do not share the same name */ - if (0 != circuit_lib.port_lib_name(global_ports[iport]).compare(circuit_lib.port_lib_name(global_ports[jport]))) { + if (0 != circuit_lib.port_prefix(global_ports[iport]).compare(circuit_lib.port_prefix(global_ports[jport]))) { continue; } @@ -421,7 +421,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) { if (circuit_lib.port_default_value(global_ports[iport]) != circuit_lib.port_default_value(global_ports[jport])) { vpr_printf(TIO_MESSAGE_ERROR, "Global ports %s from circuit model %s and %s share the same name but have different dfefault values(%lu and %lu)!\n", - circuit_lib.port_lib_name(global_ports[iport]).c_str(), + circuit_lib.port_prefix(global_ports[iport]).c_str(), circuit_lib.model_name(iport_parent_model).c_str(), circuit_lib.model_name(jport_parent_model).c_str(), circuit_lib.port_default_value(global_ports[iport]), @@ -433,7 +433,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) { if (circuit_lib.port_is_reset(global_ports[iport]) != circuit_lib.port_is_reset(global_ports[jport])) { vpr_printf(TIO_MESSAGE_ERROR, "Global ports %s from circuit model %s and %s share the same name but have different is_reset attributes!\n", - circuit_lib.port_lib_name(global_ports[iport]).c_str(), + circuit_lib.port_prefix(global_ports[iport]).c_str(), circuit_lib.model_name(iport_parent_model).c_str(), circuit_lib.model_name(jport_parent_model).c_str() ); @@ -442,7 +442,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) { if (circuit_lib.port_is_set(global_ports[iport]) != circuit_lib.port_is_set(global_ports[jport])) { vpr_printf(TIO_MESSAGE_ERROR, "Global ports %s from circuit model %s and %s share the same name but have different is_set attributes!\n", - circuit_lib.port_lib_name(global_ports[iport]).c_str(), + circuit_lib.port_prefix(global_ports[iport]).c_str(), circuit_lib.model_name(iport_parent_model).c_str(), circuit_lib.model_name(jport_parent_model).c_str() ); @@ -451,7 +451,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) { if (circuit_lib.port_is_config_enable(global_ports[iport]) != circuit_lib.port_is_config_enable(global_ports[jport])) { vpr_printf(TIO_MESSAGE_ERROR, "Global ports %s from circuit model %s and %s share the same name but have different is_config_enable attributes!\n", - circuit_lib.port_lib_name(global_ports[iport]).c_str(), + circuit_lib.port_prefix(global_ports[iport]).c_str(), circuit_lib.model_name(iport_parent_model).c_str(), circuit_lib.model_name(jport_parent_model).c_str() ); @@ -460,7 +460,7 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) { if (circuit_lib.port_is_prog(global_ports[iport]) != circuit_lib.port_is_prog(global_ports[jport])) { vpr_printf(TIO_MESSAGE_ERROR, "Global ports %s from circuit model %s and %s share the same name but have different is_prog attributes!\n", - circuit_lib.port_lib_name(global_ports[iport]).c_str(), + circuit_lib.port_prefix(global_ports[iport]).c_str(), circuit_lib.model_name(iport_parent_model).c_str(), circuit_lib.model_name(jport_parent_model).c_str() ); diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp b/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp index 7c3a24d94..22145b38f 100644 --- a/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library_utils.cpp @@ -226,7 +226,7 @@ std::vector find_circuit_library_global_ports(const CircuitLibrar /* Check if a same port with the same name has already been in the list */ bool add_to_list = true; for (const auto& global_port : global_ports) { - if (0 == circuit_lib.port_lib_name(port).compare(circuit_lib.port_lib_name(global_port))) { + if (0 == circuit_lib.port_prefix(port).compare(circuit_lib.port_prefix(global_port))) { /* Same name, skip list update */ add_to_list = false; break; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp index bdd636071..3b6b0a6f0 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.cpp @@ -462,6 +462,15 @@ ModulePortId ModuleManager::add_port(const ModuleId& module, return port; } +/* Set a name for a module port */ +void ModuleManager::set_module_port_name(const ModuleId& module, const ModulePortId& module_port, + const std::string& port_name) { + /* Validate the id of module port */ + VTR_ASSERT( valid_module_port_id(module, module_port) ); + + ports_[module][module_port].set_name(port_name); +} + /* Set a name for a module */ void ModuleManager::set_module_name(const ModuleId& module, const std::string& name) { /* Validate the id of module */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h index 1efcd0d24..ac7096fd3 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager.h @@ -127,6 +127,8 @@ class ModuleManager { /* Add a port to a module */ ModulePortId add_port(const ModuleId& module, const BasicPort& port_info, const enum e_module_port_type& port_type); + /* Set a name for a module port */ + void set_module_port_name(const ModuleId& module, const ModulePortId& module_port, const std::string& port_name); /* Set a name for a module */ void set_module_name(const ModuleId& module, const std::string& name); /* Set a port to be a wire */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp index cabd6ba00..f8c79a238 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp @@ -36,7 +36,7 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager, /* Add ports */ /* Find global ports and add one by one */ for (const auto& port : circuit_lib.model_global_ports(circuit_model, false)) { - BasicPort port_info(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + BasicPort port_info(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); module_manager.add_port(module, port_info, ModuleManager::MODULE_GLOBAL_PORT); } @@ -56,7 +56,7 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager, /* Input ports (ignore all the global ports when searching the circuit_lib */ for (const auto& kv : port_type2type_map) { for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, kv.first, true)) { - BasicPort port_info(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + BasicPort port_info(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); module_manager.add_port(module, port_info, kv.second); } } @@ -397,7 +397,7 @@ void add_primitive_pb_type_module_nets(ModuleManager& module_manager, BasicPort src_port = module_manager.module_port(pb_type_module, src_module_port_id); /* Get the des module port id */ - std::string des_module_port_name = circuit_lib.port_lib_name(pb_type_port->circuit_model_port); + std::string des_module_port_name = circuit_lib.port_prefix(pb_type_port->circuit_model_port); ModulePortId des_module_port_id = module_manager.find_module_port(child_module, des_module_port_name); VTR_ASSERT(ModulePortId::INVALID() != des_module_port_id); BasicPort des_port = module_manager.module_port(child_module, des_module_port_id); @@ -558,11 +558,11 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man std::vector logic_model_sram_port_names; /* Regular sram port goes first */ for (CircuitPortId regular_sram_port : find_circuit_regular_sram_ports(circuit_lib, logic_model)) { - logic_model_sram_port_names.push_back(circuit_lib.port_lib_name(regular_sram_port)); + logic_model_sram_port_names.push_back(circuit_lib.port_prefix(regular_sram_port)); } /* Mode-select sram port goes first */ for (CircuitPortId mode_select_sram_port : find_circuit_mode_select_sram_ports(circuit_lib, logic_model)) { - logic_model_sram_port_names.push_back(circuit_lib.port_lib_name(mode_select_sram_port)); + logic_model_sram_port_names.push_back(circuit_lib.port_prefix(mode_select_sram_port)); } /* Find the port ids in the memory */ std::vector logic_module_sram_port_ids; @@ -594,11 +594,11 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man std::vector logic_model_sramb_port_names; /* Regular sram port goes first */ for (CircuitPortId regular_sram_port : find_circuit_regular_sram_ports(circuit_lib, logic_model)) { - logic_model_sramb_port_names.push_back(circuit_lib.port_lib_name(regular_sram_port) + std::string("_inv")); + logic_model_sramb_port_names.push_back(circuit_lib.port_prefix(regular_sram_port) + std::string("_inv")); } /* Mode-select sram port goes first */ for (CircuitPortId mode_select_sram_port : find_circuit_mode_select_sram_ports(circuit_lib, logic_model)) { - logic_model_sramb_port_names.push_back(circuit_lib.port_lib_name(mode_select_sram_port) + std::string("_inv")); + logic_model_sramb_port_names.push_back(circuit_lib.port_prefix(mode_select_sram_port) + std::string("_inv")); } /* Find the port ids in the memory */ std::vector logic_module_sramb_port_ids; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_device_module.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_device_module.cpp index 49b904257..772ee8f57 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_device_module.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_device_module.cpp @@ -132,6 +132,15 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup, arch.sram_inf.verilog_sram_inf_orgz->type, sram_model, TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy); + /* Now a critical correction has to be done! + * In the module construction, we always use prefix of ports because they are binded + * to the ports in architecture description (logic blocks etc.) + * To interface with standard cell, we should + * rename the ports of primitive modules using lib_name instead of prefix + * (which have no children and are probably linked to a standard cell!) + */ + rename_primitive_module_port_names(module_manager, arch.spice->circuit_lib); + /* End time count */ clock_t t_end = clock(); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp index a474ab26c..ca2b17a1b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp @@ -232,7 +232,7 @@ void build_user_defined_modules(ModuleManager& module_manager, VTR_ASSERT (1 == circuit_lib.port_size(output_ports[0])); /* Add a mid-output port to the module */ - BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_lib_name(output_ports[0])), circuit_lib.port_size(output_ports[0])); + BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_prefix(output_ports[0])), circuit_lib.port_size(output_ports[0])); module_manager.add_port(module_id, module_mid_output_port, ModuleManager::MODULE_OUTPUT_PORT); } @@ -288,3 +288,40 @@ void build_constant_generator_modules(ModuleManager& module_manager) { "took %.2g seconds\n", run_time_sec); } + +/********************************************************************* + * This function will rename the ports of primitive modules + * using lib_name instead of prefix + * Primitive modules are defined as those modules in the module manager + * which have user defined netlists + ********************************************************************/ +void rename_primitive_module_port_names(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib) { + for (const CircuitModelId& model : circuit_lib.models()) { + /* We only care about user-defined models */ + if ( (true == circuit_lib.model_verilog_netlist(model).empty()) + && (true == circuit_lib.model_verilog_netlist(model).empty()) ) { + continue; + } + /* Skip Routing channel wire models because they need a different name. Do it later */ + if (SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(model)) { + continue; + } + /* Find the module in module manager */ + ModuleId module = module_manager.find_module(circuit_lib.model_name(model)); + /* We must find one! */ + VTR_ASSERT(true == module_manager.valid_module_id(module)); + + /* Rename all the ports to use lib_name! */ + for (const CircuitPortId& model_port : circuit_lib.model_ports(model)) { + /* Find the module port in module manager. We used prefix when creating the ports */ + ModulePortId module_port = module_manager.find_module_port(module, circuit_lib.port_prefix(model_port)); + /* We must find one! */ + VTR_ASSERT(true == module_manager.valid_module_port_id(module, module_port)); + /* Name it with lib_name */ + module_manager.set_module_port_name(module, module_port, circuit_lib.port_lib_name(model_port)); + } + } +} + + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.h b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.h index 34200f68b..417f265b6 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.h @@ -13,4 +13,7 @@ void build_user_defined_modules(ModuleManager& module_manager, void build_constant_generator_modules(ModuleManager& module_manager); +void rename_primitive_module_port_names(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp index 57eca34e7..b298c22c1 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp @@ -369,7 +369,7 @@ void build_primitive_block_module(ModuleManager& module_manager, for (auto port : primitive_model_inout_ports) { BasicPort module_port(generate_fpga_global_io_port_name(std::string(gio_inout_prefix), circuit_lib, primitive_model), circuit_lib.port_size(port)); ModulePortId primitive_gpio_port_id = module_manager.add_port(primitive_module, module_port, ModuleManager::MODULE_GPIO_PORT); - ModulePortId logic_gpio_port_id = module_manager.find_module_port(logic_module, circuit_lib.port_lib_name(port)); + ModulePortId logic_gpio_port_id = module_manager.find_module_port(logic_module, circuit_lib.port_prefix(port)); BasicPort logic_gpio_port = module_manager.module_port(logic_module, logic_gpio_port_id); VTR_ASSERT(logic_gpio_port.get_width() == module_port.get_width()); @@ -530,7 +530,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager, /* First net is to connect input of src_pb_graph_node to input of the wire module */ add_module_pb_graph_pin2pin_net(module_manager, pb_module, wire_module, wire_instance, - circuit_lib.port_lib_name(interc_model_inputs[0]), + circuit_lib.port_prefix(interc_model_inputs[0]), 0, /* wire input port has only 1 pin */ module_name_prefix, src_pb_graph_pin, @@ -539,7 +539,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager, /* Second net is to connect output of the wire module to output of des_pb_graph_pin */ add_module_pb_graph_pin2pin_net(module_manager, pb_module, wire_module, wire_instance, - circuit_lib.port_lib_name(interc_model_outputs[0]), + circuit_lib.port_prefix(interc_model_outputs[0]), 0, /* wire output port has only 1 pin */ module_name_prefix, des_pb_graph_pin, @@ -610,7 +610,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager, /* Add a net, set its source and sink */ add_module_pb_graph_pin2pin_net(module_manager, pb_module, mux_module, mux_instance, - circuit_lib.port_lib_name(interc_model_inputs[0]), + circuit_lib.port_prefix(interc_model_inputs[0]), mux_input_pin_id, module_name_prefix, src_pb_graph_pin, @@ -623,7 +623,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager, /* Add a net to wire the output of the multiplexer to des_pb_graph_pin */ add_module_pb_graph_pin2pin_net(module_manager, pb_module, mux_module, mux_instance, - circuit_lib.port_lib_name(interc_model_outputs[0]), + circuit_lib.port_prefix(interc_model_outputs[0]), 0, /* MUX should have only 1 pin in its output port */ module_name_prefix, des_pb_graph_pin, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.cpp index 75795bd50..3122cf178 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.cpp @@ -82,36 +82,36 @@ void build_lut_module(ModuleManager& module_manager, /* Add each global port */ for (const auto& port : lut_global_ports) { /* Configure each global port */ - BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + BasicPort global_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); module_manager.add_port(lut_module, global_port, ModuleManager::MODULE_GLOBAL_PORT); } /* Add each input port */ for (const auto& port : lut_input_ports) { - BasicPort input_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + BasicPort input_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); module_manager.add_port(lut_module, input_port, ModuleManager::MODULE_INPUT_PORT); /* Set the port to be wire-connection */ module_manager.set_port_is_wire(lut_module, input_port.get_name(), true); } /* Add each output port */ for (const auto& port : lut_output_ports) { - BasicPort output_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + BasicPort output_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); module_manager.add_port(lut_module, output_port, ModuleManager::MODULE_OUTPUT_PORT); /* Set the port to be wire-connection */ module_manager.set_port_is_wire(lut_module, output_port.get_name(), true); } /* Add each regular (not mode select) SRAM port */ for (const auto& port : lut_regular_sram_ports) { - BasicPort mem_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + BasicPort mem_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); module_manager.add_port(lut_module, mem_port, ModuleManager::MODULE_INPUT_PORT); - BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), circuit_lib.port_size(port)); + BasicPort mem_inv_port(std::string(circuit_lib.port_prefix(port) + "_inv"), circuit_lib.port_size(port)); module_manager.add_port(lut_module, mem_inv_port, ModuleManager::MODULE_INPUT_PORT); } /* Add each mode-select SRAM port */ for (const auto& port : lut_mode_select_sram_ports) { - BasicPort mem_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + BasicPort mem_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); module_manager.add_port(lut_module, mem_port, ModuleManager::MODULE_INPUT_PORT); - BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), circuit_lib.port_size(port)); + BasicPort mem_inv_port(std::string(circuit_lib.port_prefix(port) + "_inv"), circuit_lib.port_size(port)); module_manager.add_port(lut_module, mem_inv_port, ModuleManager::MODULE_INPUT_PORT); } @@ -149,7 +149,7 @@ void build_lut_module(ModuleManager& module_manager, std::string tri_state_map = circuit_lib.port_tri_state_map(lut_input_ports[0]); size_t mode_select_port_lsb = 0; for (const auto& pin : circuit_lib.pins(lut_input_ports[0])) { - ModulePortId lut_module_input_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(lut_input_ports[0])); + ModulePortId lut_module_input_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_input_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(lut_module, lut_module_input_port_id)); /* Create a module net for the connection */ @@ -222,13 +222,13 @@ void build_lut_module(ModuleManager& module_manager, ModuleNetId gate_sram_net = module_manager.create_module_net(lut_module); /* Find the module port id of the SRAM port of LUT module */ - ModulePortId lut_module_mode_select_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(lut_mode_select_sram_ports[0])); + ModulePortId lut_module_mode_select_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_mode_select_sram_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(lut_module, lut_module_mode_select_port_id)); /* Set the source of the net to an mode-select SRAM port of the LUT module */ module_manager.add_module_net_source(lut_module, gate_sram_net, lut_module, 0, lut_module_mode_select_port_id, mode_select_port_lsb); /* Find the module port id of the SRAM port of LUT module */ - ModulePortId gate_module_input0_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_lib_name(gate_input_ports[0])); + ModulePortId gate_module_input0_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_prefix(gate_input_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(gate_module, gate_module_input0_port_id)); /* Set the sink of the net to an input[0] port of the gate module */ VTR_ASSERT(1 == module_manager.module_port(gate_module, gate_module_input0_port_id).get_width()); @@ -237,7 +237,7 @@ void build_lut_module(ModuleManager& module_manager, } /* Use the existing net to connect to the input[1] port of the gate module */ - ModulePortId gate_module_input1_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_lib_name(gate_input_ports[1])); + ModulePortId gate_module_input1_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_prefix(gate_input_ports[1])); VTR_ASSERT(true == module_manager.valid_module_port_id(gate_module, gate_module_input1_port_id)); VTR_ASSERT(1 == module_manager.module_port(gate_module, gate_module_input1_port_id).get_width()); for (const size_t& gate_pin : module_manager.module_port(gate_module, gate_module_input1_port_id).pins()) { @@ -246,7 +246,7 @@ void build_lut_module(ModuleManager& module_manager, /* Create a module net for the output connection */ ModuleNetId gate_output_net = module_manager.create_module_net(lut_module); - ModulePortId gate_module_output_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_lib_name(gate_output_ports[0])); + ModulePortId gate_module_output_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_prefix(gate_output_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(gate_module, gate_module_output_port_id)); BasicPort gate_module_output_port = module_manager.module_port(gate_module, gate_module_output_port_id); VTR_ASSERT(1 == gate_module_output_port.get_width()); @@ -326,7 +326,7 @@ void build_lut_module(ModuleManager& module_manager, * 3. Data input of LUT MUX module to SRAM port of LUT * 4. Data output of LUT MUX module to output ports of LUT */ - ModulePortId lut_mux_sram_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_lib_name(lut_regular_sram_ports[0])); + ModulePortId lut_mux_sram_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(lut_regular_sram_ports[0])); BasicPort lut_mux_sram_port = module_manager.module_port(lut_mux_module, lut_mux_sram_port_id); VTR_ASSERT(lut_mux_sram_port.get_width() == lut_mux_sram_nets.size()); /* Wire the port to lut_mux_sram_net */ @@ -334,7 +334,7 @@ void build_lut_module(ModuleManager& module_manager, module_manager.add_module_net_sink(lut_module, lut_mux_sram_nets[pin], lut_mux_module, lut_mux_instance, lut_mux_sram_port_id, pin); } - ModulePortId lut_mux_sram_inv_port_id = module_manager.find_module_port(lut_mux_module, std::string(circuit_lib.port_lib_name(lut_regular_sram_ports[0]) + "_inv")); + ModulePortId lut_mux_sram_inv_port_id = module_manager.find_module_port(lut_mux_module, std::string(circuit_lib.port_prefix(lut_regular_sram_ports[0]) + "_inv")); BasicPort lut_mux_sram_inv_port = module_manager.module_port(lut_mux_module, lut_mux_sram_inv_port_id); VTR_ASSERT(lut_mux_sram_inv_port.get_width() == lut_mux_sram_inv_nets.size()); /* Wire the port to lut_mux_sram_net */ @@ -351,9 +351,9 @@ void build_lut_module(ModuleManager& module_manager, * | * net */ - ModulePortId lut_sram_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(lut_regular_sram_ports[0])); + ModulePortId lut_sram_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_regular_sram_ports[0])); BasicPort lut_sram_port = module_manager.module_port(lut_module, lut_sram_port_id); - ModulePortId lut_mux_input_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_lib_name(lut_input_ports[0])); + ModulePortId lut_mux_input_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(lut_input_ports[0])); BasicPort lut_mux_input_port = module_manager.module_port(lut_mux_module, lut_mux_input_port_id); VTR_ASSERT(lut_mux_input_port.get_width() == lut_sram_port.get_width()); /* Wire the port to lut_mux_sram_net */ @@ -364,9 +364,9 @@ void build_lut_module(ModuleManager& module_manager, } for (const auto& port : lut_output_ports) { - ModulePortId lut_output_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(port)); + ModulePortId lut_output_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(port)); BasicPort lut_output_port = module_manager.module_port(lut_module, lut_output_port_id); - ModulePortId lut_mux_output_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_lib_name(port)); + ModulePortId lut_mux_output_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(port)); BasicPort lut_mux_output_port = module_manager.module_port(lut_mux_module, lut_mux_output_port_id); VTR_ASSERT(lut_mux_output_port.get_width() == lut_output_port.get_width()); /* Wire the port to lut_mux_sram_net */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp index 718b47cdb..a4a33bed2 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_memory_modules.cpp @@ -48,8 +48,8 @@ void add_module_input_nets_to_mem_modules(ModuleManager& module_manager, const size_t& child_instance) { /* Wire inputs of parent module to inputs of child modules */ for (const auto& port : circuit_ports) { - ModulePortId src_port_id = module_manager.find_module_port(mem_module, circuit_lib.port_lib_name(port)); - ModulePortId sink_port_id = module_manager.find_module_port(child_module, circuit_lib.port_lib_name(port)); + ModulePortId src_port_id = module_manager.find_module_port(mem_module, circuit_lib.port_prefix(port)); + ModulePortId sink_port_id = module_manager.find_module_port(child_module, circuit_lib.port_prefix(port)); for (size_t pin_id = 0; pin_id < module_manager.module_port(mem_module, sink_port_id).pins().size(); ++pin_id) { ModuleNetId net = module_manager.create_module_net(mem_module); /* Source pin is shifted by the number of memories */ @@ -82,8 +82,8 @@ void add_module_output_nets_to_mem_modules(ModuleManager& module_manager, const size_t& child_instance) { /* Wire inputs of parent module to inputs of child modules */ for (const auto& port : circuit_ports) { - ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_lib_name(port)); - ModulePortId sink_port_id = module_manager.find_module_port(mem_module, circuit_lib.port_lib_name(port)); + ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_prefix(port)); + ModulePortId sink_port_id = module_manager.find_module_port(mem_module, circuit_lib.port_prefix(port)); for (size_t pin_id = 0; pin_id < module_manager.module_port(child_module, src_port_id).pins().size(); ++pin_id) { ModuleNetId net = module_manager.create_module_net(mem_module); /* Source pin is shifted by the number of memories */ @@ -121,7 +121,7 @@ std::vector add_module_output_nets_to_chain_mem_modules(ModuleManag std::vector module_nets; /* Wire inputs of parent module to inputs of child modules */ - ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_lib_name(circuit_port)); + ModulePortId src_port_id = module_manager.find_module_port(child_module, circuit_lib.port_prefix(circuit_port)); ModulePortId sink_port_id = module_manager.find_module_port(mem_module, mem_module_output_name); for (size_t pin_id = 0; pin_id < module_manager.module_port(child_module, src_port_id).pins().size(); ++pin_id) { ModuleNetId net = module_manager.create_module_net(mem_module); @@ -188,19 +188,19 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager, net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); /* Find the port name of next memory module */ - std::string sink_port_name = circuit_lib.port_lib_name(model_input_port); + std::string sink_port_name = circuit_lib.port_prefix(model_input_port); net_sink_module_id = module_manager.configurable_children(parent_module)[mem_index]; net_sink_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index]; net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); } else { /* Find the port name of previous memory module */ - std::string src_port_name = circuit_lib.port_lib_name(model_output_port); + std::string src_port_name = circuit_lib.port_prefix(model_output_port); net_src_module_id = module_manager.configurable_children(parent_module)[mem_index - 1]; net_src_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index - 1]; net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); /* Find the port name of next memory module */ - std::string sink_port_name = circuit_lib.port_lib_name(model_input_port); + std::string sink_port_name = circuit_lib.port_prefix(model_input_port); net_sink_module_id = module_manager.configurable_children(parent_module)[mem_index]; net_sink_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index]; net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); @@ -239,7 +239,7 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager, * net sink is the configuration chain tail of the primitive module */ /* Find the port name of previous memory module */ - std::string src_port_name = circuit_lib.port_lib_name(model_output_port); + std::string src_port_name = circuit_lib.port_prefix(model_output_port); ModuleId net_src_module_id = module_manager.configurable_children(parent_module).back(); size_t net_src_instance_id = module_manager.configurable_child_instances(parent_module).back(); ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); @@ -311,12 +311,12 @@ void build_memory_standalone_module(ModuleManager& module_manager, /* Add each input port */ for (const auto& port : sram_input_ports) { - BasicPort input_port(circuit_lib.port_lib_name(port), num_mems); + BasicPort input_port(circuit_lib.port_prefix(port), num_mems); module_manager.add_port(mem_module, input_port, ModuleManager::MODULE_INPUT_PORT); } /* Add each output port: port width should match the number of memories */ for (const auto& port : sram_output_ports) { - BasicPort output_port(circuit_lib.port_lib_name(port), num_mems); + BasicPort output_port(circuit_lib.port_prefix(port), num_mems); module_manager.add_port(mem_module, output_port, ModuleManager::MODULE_OUTPUT_PORT); } @@ -500,29 +500,29 @@ void build_memory_bank_module(ModuleManager& module_manager, /* Add module ports: the ports come from the SRAM modules */ /* Add each input port */ for (const auto& port : sram_input_ports) { - BasicPort input_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + BasicPort input_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port)); module_manager.add_port(mem_module, input_port, ModuleManager::MODULE_INPUT_PORT); } /* Add each output port: port width should match the number of memories */ for (const auto& port : sram_output_ports) { - BasicPort output_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + BasicPort output_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port)); module_manager.add_port(mem_module, output_port, ModuleManager::MODULE_OUTPUT_PORT); } /* Add each output port: port width should match the number of memories */ for (const auto& port : sram_bl_ports) { - BasicPort bl_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + BasicPort bl_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port)); module_manager.add_port(mem_module, bl_port, ModuleManager::MODULE_INPUT_PORT); } for (const auto& port : sram_blb_ports) { - BasicPort blb_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + BasicPort blb_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port)); module_manager.add_port(mem_module, blb_port, ModuleManager::MODULE_INPUT_PORT); } for (const auto& port : sram_wl_ports) { - BasicPort wl_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + BasicPort wl_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port)); module_manager.add_port(mem_module, wl_port, ModuleManager::MODULE_INPUT_PORT); } for (const auto& port : sram_wlb_ports) { - BasicPort wlb_port(circuit_lib.port_lib_name(port), num_mems * circuit_lib.port_size(port)); + BasicPort wlb_port(circuit_lib.port_prefix(port), num_mems * circuit_lib.port_size(port)); module_manager.add_port(mem_module, wlb_port, ModuleManager::MODULE_INPUT_PORT); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_mux_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_mux_modules.cpp index 529f1e760..3d550d9ee 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_mux_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_mux_modules.cpp @@ -74,25 +74,25 @@ void build_cmos_mux_branch_body(ModuleManager& module_manager, /* Find the module ports of tgate module */ /* Input port is the data path input of the tgate, whose size must be 1 ! */ - ModulePortId tgate_module_input = module_manager.find_module_port(tgate_module_id, circuit_lib.port_lib_name(tgate_input_ports[0])); + ModulePortId tgate_module_input = module_manager.find_module_port(tgate_module_id, circuit_lib.port_prefix(tgate_input_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(tgate_module_id, tgate_module_input)); BasicPort tgate_module_input_port = module_manager.module_port(tgate_module_id, tgate_module_input); VTR_ASSERT(1 == tgate_module_input_port.get_width()); /* Mem port is the memory of the tgate, whose size must be 1 ! */ - ModulePortId tgate_module_mem = module_manager.find_module_port(tgate_module_id, circuit_lib.port_lib_name(tgate_input_ports[1])); + ModulePortId tgate_module_mem = module_manager.find_module_port(tgate_module_id, circuit_lib.port_prefix(tgate_input_ports[1])); VTR_ASSERT(true == module_manager.valid_module_port_id(tgate_module_id, tgate_module_mem)); BasicPort tgate_module_mem_port = module_manager.module_port(tgate_module_id, tgate_module_mem); VTR_ASSERT(1 == tgate_module_mem_port.get_width()); /* Mem inv port is the inverted memory of the tgate, whose size must be 1 ! */ - ModulePortId tgate_module_mem_inv = module_manager.find_module_port(tgate_module_id, circuit_lib.port_lib_name(tgate_input_ports[2])); + ModulePortId tgate_module_mem_inv = module_manager.find_module_port(tgate_module_id, circuit_lib.port_prefix(tgate_input_ports[2])); VTR_ASSERT(true == module_manager.valid_module_port_id(tgate_module_id, tgate_module_mem_inv)); BasicPort tgate_module_mem_inv_port = module_manager.module_port(tgate_module_id, tgate_module_mem_inv); VTR_ASSERT(1 == tgate_module_mem_inv_port.get_width()); /* Output port is the data path output of the tgate, whose size must be 1 ! */ - ModulePortId tgate_module_output = module_manager.find_module_port(tgate_module_id, circuit_lib.port_lib_name(tgate_output_ports[0])); + ModulePortId tgate_module_output = module_manager.find_module_port(tgate_module_id, circuit_lib.port_prefix(tgate_output_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(tgate_module_id, tgate_module_output)); BasicPort tgate_module_output_port = module_manager.module_port(tgate_module_id, tgate_module_output); VTR_ASSERT(1 == tgate_module_output_port.get_width()); @@ -300,26 +300,26 @@ void build_rram_mux_branch_module(ModuleManager& module_manager, std::vector prog_enable_ports = circuit_lib.model_global_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true, true); for (const auto& port : prog_enable_ports) { /* Configure each global port */ - BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + BasicPort global_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); module_manager.add_port(mux_module, global_port, ModuleManager::MODULE_GLOBAL_PORT); } /* Add each input port */ - BasicPort input_port(circuit_lib.port_lib_name(mux_input_ports[0]), num_inputs); + BasicPort input_port(circuit_lib.port_prefix(mux_input_ports[0]), num_inputs); module_manager.add_port(mux_module, input_port, ModuleManager::MODULE_INPUT_PORT); /* Add each output port */ - BasicPort output_port(circuit_lib.port_lib_name(mux_output_ports[0]), num_outputs); + BasicPort output_port(circuit_lib.port_prefix(mux_output_ports[0]), num_outputs); module_manager.add_port(mux_module, output_port, ModuleManager::MODULE_OUTPUT_PORT); /* Add RRAM programming ports, * RRAM MUXes require one more pair of BLB and WL * to configure the memories. See schematic for details */ - BasicPort blb_port(circuit_lib.port_lib_name(mux_blb_ports[0]), num_mems + 1); + BasicPort blb_port(circuit_lib.port_prefix(mux_blb_ports[0]), num_mems + 1); module_manager.add_port(mux_module, blb_port, ModuleManager::MODULE_INPUT_PORT); - BasicPort wl_port(circuit_lib.port_lib_name(mux_wl_ports[0]), num_mems + 1); + BasicPort wl_port(circuit_lib.port_prefix(mux_wl_ports[0]), num_mems + 1); module_manager.add_port(mux_module, wl_port, ModuleManager::MODULE_INPUT_PORT); /* Note: we do not generate the internal structure of the ReRAM-based MUX @@ -398,20 +398,20 @@ void build_cmos_mux_module_mux2_multiplexing_structure(ModuleManager& module_man std::vector std_cell_module_input_ports; /* Input 0 port is the first data path input of the tgate, whose size must be 1 ! */ for (size_t port_id = 0; port_id < 2; ++port_id) { - std_cell_module_inputs.push_back(module_manager.find_module_port(std_cell_module_id, circuit_lib.port_lib_name(std_cell_input_ports[port_id]))); + std_cell_module_inputs.push_back(module_manager.find_module_port(std_cell_module_id, circuit_lib.port_prefix(std_cell_input_ports[port_id]))); VTR_ASSERT(true == module_manager.valid_module_port_id(std_cell_module_id, std_cell_module_inputs[port_id])); std_cell_module_input_ports.push_back(module_manager.module_port(std_cell_module_id, std_cell_module_inputs[port_id])); VTR_ASSERT(1 == std_cell_module_input_ports[port_id].get_width()); } /* Mem port is the memory of the standard cell MUX2, whose size must be 1 ! */ - ModulePortId std_cell_module_mem = module_manager.find_module_port(std_cell_module_id, circuit_lib.port_lib_name(std_cell_input_ports[2])); + ModulePortId std_cell_module_mem = module_manager.find_module_port(std_cell_module_id, circuit_lib.port_prefix(std_cell_input_ports[2])); VTR_ASSERT(true == module_manager.valid_module_port_id(std_cell_module_id, std_cell_module_mem)); BasicPort std_cell_module_mem_port = module_manager.module_port(std_cell_module_id, std_cell_module_mem); VTR_ASSERT(1 == std_cell_module_mem_port.get_width()); /* Output port is the data path output of the standard cell MUX2, whose size must be 1 ! */ - ModulePortId std_cell_module_output = module_manager.find_module_port(std_cell_module_id, circuit_lib.port_lib_name(std_cell_output_ports[0])); + ModulePortId std_cell_module_output = module_manager.find_module_port(std_cell_module_id, circuit_lib.port_prefix(std_cell_output_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(std_cell_module_id, std_cell_module_output)); BasicPort std_cell_module_output_port = module_manager.module_port(std_cell_module_id, std_cell_module_output); VTR_ASSERT(1 == std_cell_module_output_port.get_width()); @@ -745,7 +745,7 @@ vtr::vector build_mux_module_input_buffers(ModuleManage VTR_ASSERT(1 == mux_input_ports.size()); /* Get the input port from MUX module */ - ModulePortId module_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_input_ports[0])); + ModulePortId module_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_input_ports[0])); VTR_ASSERT(ModulePortId::INVALID() != module_input_port_id); /* Get the port from module */ BasicPort module_input_port = module_manager.module_port(mux_module, module_input_port_id); @@ -860,7 +860,7 @@ vtr::vector build_mux_module_output_buffers(ModuleMana /* Iterate over all the outputs in the MUX module */ for (const auto& output_port : mux_output_ports) { /* Get the output port from MUX module */ - ModulePortId module_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(output_port)); + ModulePortId module_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(output_port)); VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id); /* Get the port from module */ BasicPort module_output_port = module_manager.module_port(mux_module, module_output_port_id); @@ -968,7 +968,7 @@ void build_mux_module_local_encoders_and_memory_nets(ModuleManager& module_manag /* Add mem and mem_inv nets here */ size_t mem_net_cnt = 0; for (const auto& port : mux_sram_ports) { - ModulePortId mem_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(port)); + ModulePortId mem_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(port)); BasicPort mem_port = module_manager.module_port(mux_module, mem_port_id); for (const size_t& pin : mem_port.pins()) { MuxMemId mem_id = MuxMemId(mem_net_cnt); @@ -983,7 +983,7 @@ void build_mux_module_local_encoders_and_memory_nets(ModuleManager& module_manag /* Add mem and mem_inv nets here */ size_t mem_inv_net_cnt = 0; for (const auto& port : mux_sram_ports) { - ModulePortId mem_inv_port_id = module_manager.find_module_port(mux_module, std::string(circuit_lib.port_lib_name(port) + "_inv")); + ModulePortId mem_inv_port_id = module_manager.find_module_port(mux_module, std::string(circuit_lib.port_prefix(port) + "_inv")); BasicPort mem_inv_port = module_manager.module_port(mux_module, mem_inv_port_id); for (const size_t& pin : mem_inv_port.pins()) { MuxMemId mem_id = MuxMemId(mem_inv_net_cnt); @@ -1003,9 +1003,9 @@ void build_mux_module_local_encoders_and_memory_nets(ModuleManager& module_manag BasicPort decoder_data_inv_port(generate_mux_local_decoder_data_inv_port_name(), mux_graph.num_memory_bits()); /* Local port to record the LSB and MSB of each level, here, we deposite (0, 0) */ - ModulePortId mux_module_sram_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_sram_ports[0])); - ModulePortId mux_module_sram_inv_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_sram_ports[0]) + "_inv"); - BasicPort lvl_addr_port(circuit_lib.port_lib_name(mux_sram_ports[0]), 0); + ModulePortId mux_module_sram_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_sram_ports[0])); + ModulePortId mux_module_sram_inv_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_sram_ports[0]) + "_inv"); + BasicPort lvl_addr_port(circuit_lib.port_prefix(mux_sram_ports[0]), 0); BasicPort lvl_data_port(decoder_data_port.get_name(), 0); BasicPort lvl_data_inv_port(decoder_data_inv_port.get_name(), 0); @@ -1161,7 +1161,7 @@ void build_cmos_mux_module(ModuleManager& module_manager, */ size_t input_port_cnt = 0; for (const auto& port : mux_input_ports) { - BasicPort input_port(circuit_lib.port_lib_name(port), num_inputs); + BasicPort input_port(circuit_lib.port_prefix(port), num_inputs); module_manager.add_port(mux_module, input_port, ModuleManager::MODULE_INPUT_PORT); /* Update counter */ input_port_cnt++; @@ -1173,7 +1173,7 @@ void build_cmos_mux_module(ModuleManager& module_manager, vtr::vector mux_input_nets = build_mux_module_input_buffers(module_manager, circuit_lib, mux_module, mux_model, mux_graph); for (const auto& port : mux_output_ports) { - BasicPort output_port(circuit_lib.port_lib_name(port), num_outputs); + BasicPort output_port(circuit_lib.port_prefix(port), num_outputs); if (SPICE_MODEL_LUT == circuit_lib.model_type(mux_model)) { output_port.set_width(circuit_lib.port_size(port)); } @@ -1185,9 +1185,9 @@ void build_cmos_mux_module(ModuleManager& module_manager, size_t sram_port_cnt = 0; for (const auto& port : mux_sram_ports) { - BasicPort mem_port(circuit_lib.port_lib_name(port), num_mems); + BasicPort mem_port(circuit_lib.port_prefix(port), num_mems); module_manager.add_port(mux_module, mem_port, ModuleManager::MODULE_INPUT_PORT); - BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), num_mems); + BasicPort mem_inv_port(std::string(circuit_lib.port_prefix(port) + "_inv"), num_mems); module_manager.add_port(mux_module, mem_inv_port, ModuleManager::MODULE_INPUT_PORT); /* Update counter */ sram_port_cnt++; @@ -1305,13 +1305,13 @@ void build_rram_mux_module(ModuleManager& module_manager, /* Add each global port */ for (const auto& port : mux_global_ports) { /* Configure each global port */ - BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + BasicPort global_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT); } /* Add each input port */ size_t input_port_cnt = 0; for (const auto& port : mux_input_ports) { - BasicPort input_port(circuit_lib.port_lib_name(port), num_inputs); + BasicPort input_port(circuit_lib.port_prefix(port), num_inputs); module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT); /* Update counter */ input_port_cnt++; @@ -1320,7 +1320,7 @@ void build_rram_mux_module(ModuleManager& module_manager, VTR_ASSERT(1 == input_port_cnt); for (const auto& port : mux_output_ports) { - BasicPort output_port(circuit_lib.port_lib_name(port), num_outputs); + BasicPort output_port(circuit_lib.port_prefix(port), num_outputs); if (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) { output_port.set_width(circuit_lib.port_size(port)); } @@ -1332,7 +1332,7 @@ void build_rram_mux_module(ModuleManager& module_manager, /* IMPORTANT: RRAM-based MUX has an additional BLB pin per level * So, the actual port width of BLB should be added by the number of levels of the MUX graph */ - BasicPort blb_port(circuit_lib.port_lib_name(port), num_mems + mux_graph.num_levels()); + BasicPort blb_port(circuit_lib.port_prefix(port), num_mems + mux_graph.num_levels()); module_manager.add_port(module_id, blb_port, ModuleManager::MODULE_INPUT_PORT); } @@ -1341,7 +1341,7 @@ void build_rram_mux_module(ModuleManager& module_manager, /* IMPORTANT: RRAM-based MUX has an additional WL pin per level * So, the actual port width of WL should be added by the number of levels of the MUX graph */ - BasicPort wl_port(circuit_lib.port_lib_name(port), num_mems + mux_graph.num_levels()); + BasicPort wl_port(circuit_lib.port_prefix(port), num_mems + mux_graph.num_levels()); module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp index 94de58fea..04842a5cc 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp @@ -259,7 +259,7 @@ void build_switch_block_mux_module(ModuleManager& module_manager, std::vector mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true); VTR_ASSERT(1 == mux_model_input_ports.size()); /* Find the module port id of the input port */ - ModulePortId mux_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_model_input_ports[0])); + ModulePortId mux_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_input_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_input_port_id)); BasicPort mux_input_port = module_manager.module_port(mux_module, mux_input_port_id); @@ -278,7 +278,7 @@ void build_switch_block_mux_module(ModuleManager& module_manager, std::vector mux_model_output_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_OUTPUT, true); VTR_ASSERT(1 == mux_model_output_ports.size()); /* Use the port name convention in the circuit library */ - ModulePortId mux_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_model_output_ports[0])); + ModulePortId mux_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_output_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_output_port_id)); BasicPort mux_output_port = module_manager.module_port(mux_module, mux_output_port_id); ModulePortId sb_output_port_id = find_switch_block_module_chan_port(module_manager, sb_module, rr_gsb, chan_side, cur_rr_node, OUT_PORT); @@ -733,7 +733,7 @@ void build_connection_block_mux_module(ModuleManager& module_manager, std::vector mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true); VTR_ASSERT(1 == mux_model_input_ports.size()); /* Find the module port id of the input port */ - ModulePortId mux_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_model_input_ports[0])); + ModulePortId mux_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_input_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_input_port_id)); BasicPort mux_input_port = module_manager.module_port(mux_module, mux_input_port_id); @@ -752,7 +752,7 @@ void build_connection_block_mux_module(ModuleManager& module_manager, std::vector mux_model_output_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_OUTPUT, true); VTR_ASSERT(1 == mux_model_output_ports.size()); /* Use the port name convention in the circuit library */ - ModulePortId mux_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_lib_name(mux_model_output_ports[0])); + ModulePortId mux_output_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_output_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_output_port_id)); BasicPort mux_output_port = module_manager.module_port(mux_module, mux_output_port_id); ModulePortId cb_output_port_id = find_connection_block_module_ipin_port(module_manager, cb_module, rr_gsb, grids, cur_rr_node); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_directs.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_directs.cpp index 536ab15c8..dafce007b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_directs.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_directs.cpp @@ -92,13 +92,13 @@ void add_module_nets_clb2clb_direct_connection(ModuleManager& module_manager, /* Find inputs and outputs of the direct circuit module */ std::vector direct_input_ports = circuit_lib.model_ports_by_type(direct.circuit_model, SPICE_MODEL_PORT_INPUT, true); VTR_ASSERT(1 == direct_input_ports.size()); - ModulePortId direct_input_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_lib_name(direct_input_ports[0])); + ModulePortId direct_input_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_prefix(direct_input_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_input_port_id)); VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_input_port_id).get_width()); std::vector direct_output_ports = circuit_lib.model_ports_by_type(direct.circuit_model, SPICE_MODEL_PORT_OUTPUT, true); VTR_ASSERT(1 == direct_output_ports.size()); - ModulePortId direct_output_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_lib_name(direct_output_ports[0])); + ModulePortId direct_output_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_prefix(direct_output_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_output_port_id)); VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_output_port_id).get_width()); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.cpp index f338110c8..6a064fa37 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.cpp @@ -93,7 +93,7 @@ void build_routing_wire_module(ModuleManager& module_manager, ModuleId wire_module = add_circuit_model_to_module_manager(module_manager, circuit_lib, wire_model, wire_subckt_name); /* Add a mid-output port to the module */ - BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_lib_name(output_ports[0])), circuit_lib.port_size(output_ports[0])); + BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_prefix(output_ports[0])), circuit_lib.port_size(output_ports[0])); module_manager.add_port(wire_module, module_mid_output_port, ModuleManager::MODULE_OUTPUT_PORT); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp index 13cd62ada..5f116f4a0 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp @@ -40,7 +40,7 @@ void print_verilog_power_gated_invbuf_body(std::fstream& fp, print_verilog_comment(fp, std::string("----- Verilog codes of a power-gated inverter -----")); /* Create a sensitive list */ - fp << "\treg " << circuit_lib.port_lib_name(output_port) << "_reg;" << std::endl; + fp << "\treg " << circuit_lib.port_prefix(output_port) << "_reg;" << std::endl; fp << "\talways @(" << std::endl; /* Power-gate port first*/ @@ -49,9 +49,9 @@ void print_verilog_power_gated_invbuf_body(std::fstream& fp, if (0 < &power_gate_port - &power_gate_ports[0]) { fp << ","; } - fp << circuit_lib.port_lib_name(power_gate_port); + fp << circuit_lib.port_prefix(power_gate_port); } - fp << circuit_lib.port_lib_name(input_port) << ") begin" << std::endl; + fp << circuit_lib.port_prefix(input_port) << ") begin" << std::endl; /* Dump the case of power-gated */ fp << "\t\tif ("; @@ -71,14 +71,14 @@ void print_verilog_power_gated_invbuf_body(std::fstream& fp, fp << "~"; } - fp << circuit_lib.port_lib_name(power_gate_port) << "[" << power_gate_pin << "])"; + fp << circuit_lib.port_prefix(power_gate_port) << "[" << power_gate_pin << "])"; port_cnt++; /* Update port counter*/ } } fp << ") begin" << std::endl; - fp << "\t\t\tassign " << circuit_lib.port_lib_name(output_port) << "_reg = "; + fp << "\t\t\tassign " << circuit_lib.port_prefix(output_port) << "_reg = "; /* Branch on the type of inverter/buffer: * 1. If this is an inverter or an tapered(multi-stage) buffer with odd number of stages, @@ -93,12 +93,12 @@ void print_verilog_power_gated_invbuf_body(std::fstream& fp, fp << "~"; } - fp << circuit_lib.port_lib_name(input_port) << ";" << std::endl; + fp << circuit_lib.port_prefix(input_port) << ";" << std::endl; fp << "\t\tend else begin" << std::endl; - fp << "\t\t\tassign " << circuit_lib.port_lib_name(output_port) << "_reg = 1'bz;" << std::endl; + fp << "\t\t\tassign " << circuit_lib.port_prefix(output_port) << "_reg = 1'bz;" << std::endl; fp << "\t\tend" << std::endl; fp << "\tend" << std::endl; - fp << "\tassign " << circuit_lib.port_lib_name(output_port) << " = " << circuit_lib.port_lib_name(output_port) << "_reg;" << std::endl; + fp << "\tassign " << circuit_lib.port_prefix(output_port) << " = " << circuit_lib.port_prefix(output_port) << "_reg;" << std::endl; } /************************************************ @@ -116,7 +116,7 @@ void print_verilog_invbuf_body(std::fstream& fp, print_verilog_comment(fp, std::string("----- Verilog codes of a regular inverter -----")); - fp << "\tassign " << circuit_lib.port_lib_name(output_port) << " = (" << circuit_lib.port_lib_name(input_port) << " === 1'bz)? $random : "; + fp << "\tassign " << circuit_lib.port_prefix(output_port) << " = (" << circuit_lib.port_prefix(input_port) << " === 1'bz)? $random : "; /* Branch on the type of inverter/buffer: * 1. If this is an inverter or an tapered(multi-stage) buffer with odd number of stages, @@ -131,7 +131,7 @@ void print_verilog_invbuf_body(std::fstream& fp, fp << "~"; } - fp << circuit_lib.port_lib_name(input_port) << ";" << std::endl; + fp << circuit_lib.port_prefix(input_port) << ";" << std::endl; } /************************************************ @@ -282,8 +282,8 @@ void print_verilog_passgate_module(ModuleManager& module_manager, /* Dump logics: we propagate input to the output when the gate is '1' * the input is blocked from output when the gate is '0' */ - fp << "\tassign " << circuit_lib.port_lib_name(output_ports[0]) << " = "; - fp << circuit_lib.port_lib_name(input_ports[1]) << " ? " << circuit_lib.port_lib_name(input_ports[0]); + fp << "\tassign " << circuit_lib.port_prefix(output_ports[0]) << " = "; + fp << circuit_lib.port_prefix(input_ports[1]) << " ? " << circuit_lib.port_prefix(input_ports[0]); fp << " : 1'bz;" << std::endl; /* Print timing info */ @@ -329,7 +329,7 @@ void print_verilog_and_or_gate_body(std::fstream& fp, for (const auto& output_port : output_ports) { for (const auto& output_pin : circuit_lib.pins(output_port)) { - BasicPort output_port_info(circuit_lib.port_lib_name(output_port), output_pin, output_pin); + BasicPort output_port_info(circuit_lib.port_prefix(output_port), output_pin, output_pin); fp << "\tassign " << generate_verilog_port(VERILOG_PORT_CONKT, output_port_info); fp << " = "; @@ -341,7 +341,7 @@ void print_verilog_and_or_gate_body(std::fstream& fp, fp << " " << gate_verilog_operator << " "; } - BasicPort input_port_info(circuit_lib.port_lib_name(input_port), input_pin, input_pin); + BasicPort input_port_info(circuit_lib.port_prefix(input_port), input_pin, input_pin); fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port_info); /* Increment the counter for port */ @@ -413,10 +413,10 @@ void print_verilog_mux2_gate_body(std::fstream& fp, * the third input is the select port */ fp << "\tassign "; - BasicPort out_port_info(circuit_lib.port_lib_name(output_ports[0]), 0, 0); - BasicPort sel_port_info(circuit_lib.port_lib_name(input_ports[2]), 0, 0); - BasicPort in0_port_info(circuit_lib.port_lib_name(input_ports[0]), 0, 0); - BasicPort in1_port_info(circuit_lib.port_lib_name(input_ports[1]), 0, 0); + BasicPort out_port_info(circuit_lib.port_prefix(output_ports[0]), 0, 0); + BasicPort sel_port_info(circuit_lib.port_prefix(input_ports[2]), 0, 0); + BasicPort in0_port_info(circuit_lib.port_prefix(input_ports[0]), 0, 0); + BasicPort in1_port_info(circuit_lib.port_prefix(input_ports[1]), 0, 0); fp << generate_verilog_port(VERILOG_PORT_CONKT, out_port_info); fp << " = "; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp index 7fd71767d..06c2e1f4c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp @@ -538,18 +538,18 @@ void generate_verilog_rram_mux_branch_module(ModuleManager& module_manager, VTR_ASSERT(true == module_manager.valid_module_id(module_id)); /* Find each input port */ - BasicPort input_port(circuit_lib.port_lib_name(mux_input_ports[0]), num_inputs); + BasicPort input_port(circuit_lib.port_prefix(mux_input_ports[0]), num_inputs); /* Find each output port */ - BasicPort output_port(circuit_lib.port_lib_name(mux_output_ports[0]), num_outputs); + BasicPort output_port(circuit_lib.port_prefix(mux_output_ports[0]), num_outputs); /* Find RRAM programming ports, * RRAM MUXes require one more pair of BLB and WL * to configure the memories. See schematic for details */ - BasicPort blb_port(circuit_lib.port_lib_name(mux_blb_ports[0]), num_mems + 1); + BasicPort blb_port(circuit_lib.port_prefix(mux_blb_ports[0]), num_mems + 1); - BasicPort wl_port(circuit_lib.port_lib_name(mux_wl_ports[0]), num_mems + 1); + BasicPort wl_port(circuit_lib.port_prefix(mux_wl_ports[0]), num_mems + 1); /* dump module definition + ports */ print_verilog_module_declaration(fp, module_manager, module_id); @@ -633,7 +633,7 @@ void generate_verilog_cmos_mux_module_input_buffers(ModuleManager& module_manage VTR_ASSERT(1 == mux_input_ports.size()); /* Get the input port from MUX module */ - ModulePortId module_input_port_id = module_manager.find_module_port(module_id, circuit_lib.port_lib_name(mux_input_ports[0])); + ModulePortId module_input_port_id = module_manager.find_module_port(module_id, circuit_lib.port_prefix(mux_input_ports[0])); VTR_ASSERT(ModulePortId::INVALID() != module_input_port_id); /* Get the port from module */ BasicPort module_input_port = module_manager.module_port(module_id, module_input_port_id); @@ -721,7 +721,7 @@ void generate_verilog_cmos_mux_module_output_buffers(ModuleManager& module_manag /* Iterate over all the outputs in the MUX module */ for (const auto& output_port : mux_output_ports) { /* Get the output port from MUX module */ - ModulePortId module_output_port_id = module_manager.find_module_port(module_id, circuit_lib.port_lib_name(output_port)); + ModulePortId module_output_port_id = module_manager.find_module_port(module_id, circuit_lib.port_prefix(output_port)); VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id); /* Get the port from module */ BasicPort module_output_port = module_manager.module_port(module_id, module_output_port_id); @@ -918,7 +918,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu for (const auto& mem : mems) { /* Generate the port info of each mem node: */ - BasicPort branch_node_blb_port(circuit_lib.port_lib_name(mux_blb_ports[0]), size_t(mem), size_t(mem)); + BasicPort branch_node_blb_port(circuit_lib.port_prefix(mux_blb_ports[0]), size_t(mem), size_t(mem)); branch_node_blb_ports.push_back(branch_node_blb_port); } /* Every stage, we have an additonal BLB and WL in controlling purpose @@ -930,7 +930,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu * * output_node_level is always larger than the mem_level by 1 */ - branch_node_blb_ports.push_back(BasicPort(circuit_lib.port_lib_name(mux_blb_ports[0]), + branch_node_blb_ports.push_back(BasicPort(circuit_lib.port_prefix(mux_blb_ports[0]), mux_graph.num_memory_bits() + output_node_level - 1, mux_graph.num_memory_bits() + output_node_level - 1) ); @@ -949,7 +949,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu } /* Link nodes to BLB ports for the branch module */ - ModulePortId module_blb_port_id = module_manager.find_module_port(branch_module_id, circuit_lib.port_lib_name(mux_blb_ports[0])); + ModulePortId module_blb_port_id = module_manager.find_module_port(branch_module_id, circuit_lib.port_prefix(mux_blb_ports[0])); VTR_ASSERT(ModulePortId::INVALID() != module_blb_port_id); /* Get the port from module */ BasicPort module_blb_port = module_manager.module_port(branch_module_id, module_blb_port_id); @@ -959,7 +959,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu for (const auto& mem : mems) { /* Generate the port info of each mem node: */ - BasicPort branch_node_blb_port(circuit_lib.port_lib_name(mux_wl_ports[0]), size_t(mem), size_t(mem)); + BasicPort branch_node_blb_port(circuit_lib.port_prefix(mux_wl_ports[0]), size_t(mem), size_t(mem)); branch_node_wl_ports.push_back(branch_node_blb_port); } /* Every stage, we have an additonal BLB and WL in controlling purpose @@ -971,7 +971,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu * * output_node_level is always larger than the mem_level by 1 */ - branch_node_wl_ports.push_back(BasicPort(circuit_lib.port_lib_name(mux_wl_ports[0]), + branch_node_wl_ports.push_back(BasicPort(circuit_lib.port_prefix(mux_wl_ports[0]), mux_graph.num_memory_bits() + output_node_level - 1, mux_graph.num_memory_bits() + output_node_level - 1) ); @@ -990,7 +990,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu } /* Link nodes to BLB ports for the branch module */ - ModulePortId module_wl_port_id = module_manager.find_module_port(branch_module_id, circuit_lib.port_lib_name(mux_wl_ports[0])); + ModulePortId module_wl_port_id = module_manager.find_module_port(branch_module_id, circuit_lib.port_prefix(mux_wl_ports[0])); VTR_ASSERT(ModulePortId::INVALID() != module_wl_port_id); /* Get the port from module */ BasicPort module_wl_port = module_manager.module_port(branch_module_id, module_wl_port_id); @@ -1107,13 +1107,13 @@ void generate_verilog_rram_mux_module(ModuleManager& module_manager, /* Add each global port */ for (const auto& port : mux_global_ports) { /* Configure each global port */ - BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + BasicPort global_port(circuit_lib.port_prefix(port), circuit_lib.port_size(port)); module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT); } /* Add each input port */ size_t input_port_cnt = 0; for (const auto& port : mux_input_ports) { - BasicPort input_port(circuit_lib.port_lib_name(port), num_inputs); + BasicPort input_port(circuit_lib.port_prefix(port), num_inputs); module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT); /* Update counter */ input_port_cnt++; @@ -1122,7 +1122,7 @@ void generate_verilog_rram_mux_module(ModuleManager& module_manager, VTR_ASSERT(1 == input_port_cnt); for (const auto& port : mux_output_ports) { - BasicPort output_port(circuit_lib.port_lib_name(port), num_outputs); + BasicPort output_port(circuit_lib.port_prefix(port), num_outputs); if (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) { output_port.set_width(circuit_lib.port_size(port)); } @@ -1134,7 +1134,7 @@ void generate_verilog_rram_mux_module(ModuleManager& module_manager, /* IMPORTANT: RRAM-based MUX has an additional BLB pin per level * So, the actual port width of BLB should be added by the number of levels of the MUX graph */ - BasicPort blb_port(circuit_lib.port_lib_name(port), num_mems + mux_graph.num_levels()); + BasicPort blb_port(circuit_lib.port_prefix(port), num_mems + mux_graph.num_levels()); module_manager.add_port(module_id, blb_port, ModuleManager::MODULE_INPUT_PORT); } @@ -1143,7 +1143,7 @@ void generate_verilog_rram_mux_module(ModuleManager& module_manager, /* IMPORTANT: RRAM-based MUX has an additional WL pin per level * So, the actual port width of WL should be added by the number of levels of the MUX graph */ - BasicPort wl_port(circuit_lib.port_lib_name(port), num_mems + mux_graph.num_levels()); + BasicPort wl_port(circuit_lib.port_prefix(port), num_mems + mux_graph.num_levels()); module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp index 9147cc053..4e955cc7f 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_preconfig_top_module.cpp @@ -120,7 +120,7 @@ void print_verilog_preconfig_top_module_connect_global_ports(std::fstream& fp, CircuitPortId linked_circuit_port_id = CircuitPortId::INVALID(); /* Find the circuit port with the same name */ for (const CircuitPortId& circuit_port_id : global_ports) { - if (0 != module_global_port.get_name().compare(circuit_lib.port_lib_name(circuit_port_id))) { + if (0 != module_global_port.get_name().compare(circuit_lib.port_prefix(circuit_port_id))) { continue; } linked_circuit_port_id = circuit_port_id; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c index a4199308d..202fae1a0 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c @@ -3134,7 +3134,7 @@ void add_user_defined_verilog_modules(ModuleManager& module_manager, VTR_ASSERT (1 == circuit_lib.port_size(output_ports[0])); /* Add a mid-output port to the module */ - BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_lib_name(output_ports[0])), circuit_lib.port_size(output_ports[0])); + BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_prefix(output_ports[0])), circuit_lib.port_size(output_ports[0])); module_manager.add_port(module_id, module_mid_output_port, ModuleManager::MODULE_OUTPUT_PORT); } } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp index 644df5246..4fcebf6c4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp @@ -109,7 +109,7 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, * connect it to the local wire of operating clock */ /* Find the module port */ - ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_lib_name(model_global_port)); + ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port)); VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); BasicPort stimuli_clock_port; @@ -141,7 +141,7 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, } /* Reach here, it means we have a configuration done port to deal with */ /* Find the module port */ - ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_lib_name(model_global_port)); + ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port)); VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); BasicPort stimuli_config_done_port(std::string(top_tb_config_done_port_name), 1); @@ -170,7 +170,7 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, } /* Reach here, it means we have a reset port to deal with */ /* Find the module port */ - ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_lib_name(model_global_port)); + ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port)); VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); BasicPort stimuli_reset_port; @@ -212,7 +212,7 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, } /* Reach here, it means we have a set port to deal with */ /* Find the module port */ - ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_lib_name(model_global_port)); + ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port)); VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); BasicPort stimuli_set_port; @@ -256,7 +256,7 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, /* Reach here, it means we have a port to deal with */ /* Find the module port and wire it to constant values */ - ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_lib_name(model_global_port)); + ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port)); VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); BasicPort module_port = module_manager.module_port(top_module, module_global_port); From 696d4a95224eb4a2111c88e15274de4139428ee5 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 16:10:00 -0700 Subject: [PATCH 32/68] remove useless channel wire module generation --- .../build_essential_modules.cpp | 27 ----- .../SRC/fpga_x2p/verilog/verilog_submodules.c | 63 +---------- .../vpr/SRC/fpga_x2p/verilog/verilog_wire.cpp | 104 +----------------- .../vpr/SRC/fpga_x2p/verilog/verilog_wire.h | 1 - 4 files changed, 5 insertions(+), 190 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp index ca2b17a1b..8ebe2ab0e 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp @@ -209,33 +209,6 @@ void build_user_defined_modules(ModuleManager& module_manager, add_circuit_model_to_module_manager(module_manager, circuit_lib, model); } - /* Register the routing channel wires */ - for (const auto& seg : routing_segments) { - VTR_ASSERT( CircuitModelId::INVALID() != seg.circuit_model); - VTR_ASSERT( SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(seg.circuit_model)); - /* We care only user-defined circuit models */ - if ( (circuit_lib.model_verilog_netlist(seg.circuit_model).empty()) - && (circuit_lib.model_verilog_netlist(seg.circuit_model).empty()) ) { - continue; - } - /* Give a unique name for subckt of wire_model of segment, - * circuit_model name is unique, and segment id is unique as well - */ - std::string segment_wire_subckt_name = generate_segment_wire_subckt_name(circuit_lib.model_name(seg.circuit_model), &seg - &routing_segments[0]); - - /* Create a Verilog Module based on the circuit model, and add to module manager */ - ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, seg.circuit_model, segment_wire_subckt_name); - - /* Find the output port*/ - std::vector output_ports = circuit_lib.model_ports_by_type(seg.circuit_model, SPICE_MODEL_PORT_OUTPUT, true); - /* Make sure the port size is what we want */ - VTR_ASSERT (1 == circuit_lib.port_size(output_ports[0])); - - /* Add a mid-output port to the module */ - BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_prefix(output_ports[0])), circuit_lib.port_size(output_ports[0])); - module_manager.add_port(module_id, module_mid_output_port, ModuleManager::MODULE_OUTPUT_PORT); - } - /* End time count */ clock_t t_end = clock(); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c index 202fae1a0..a792ed4ae 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c @@ -3085,8 +3085,7 @@ void dump_verilog_submodule_memories(t_sram_orgz_info* cur_sram_orgz_info, ********************************************************************/ static void add_user_defined_verilog_modules(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - const std::vector& routing_segments) { + const CircuitLibrary& circuit_lib) { /* Iterate over Verilog modules */ for (const auto& model : circuit_lib.models()) { /* We only care about user-defined models */ @@ -3106,37 +3105,6 @@ void add_user_defined_verilog_modules(ModuleManager& module_manager, add_circuit_model_to_module_manager(module_manager, circuit_lib, model); } } - - /* Register the routing channel wires */ - for (const auto& seg : routing_segments) { - VTR_ASSERT( CircuitModelId::INVALID() != seg.circuit_model); - VTR_ASSERT( SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(seg.circuit_model)); - /* We care only user-defined circuit models */ - if (circuit_lib.model_verilog_netlist(seg.circuit_model).empty()) { - continue; - } - /* Give a unique name for subckt of wire_model of segment, - * circuit_model name is unique, and segment id is unique as well - */ - std::string segment_wire_subckt_name = generate_segment_wire_subckt_name(circuit_lib.model_name(seg.circuit_model), &seg - &routing_segments[0]); - - /* Try to find the module in the module manager, - * If not found, create a Verilog Module based on the circuit model, - * and add to module manager */ - if (ModuleId::INVALID() != module_manager.find_module(segment_wire_subckt_name)) { - continue; - } - ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, seg.circuit_model, segment_wire_subckt_name); - - /* Find the output port*/ - std::vector output_ports = circuit_lib.model_ports_by_type(seg.circuit_model, SPICE_MODEL_PORT_OUTPUT, true); - /* Make sure the port size is what we want */ - VTR_ASSERT (1 == circuit_lib.port_size(output_ports[0])); - - /* Add a mid-output port to the module */ - BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_prefix(output_ports[0])), circuit_lib.port_size(output_ports[0])); - module_manager.add_port(module_id, module_mid_output_port, ModuleManager::MODULE_OUTPUT_PORT); - } } /* Print a template for a user-defined circuit model @@ -3186,7 +3154,6 @@ void print_one_verilog_template_module(const ModuleManager& module_manager, static void print_verilog_submodule_templates(const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, - const std::vector& routing_segments, const std::string& verilog_dir, const std::string& submodule_dir) { std::string verilog_fname(submodule_dir + user_defined_template_verilog_file_name); @@ -3220,22 +3187,6 @@ void print_verilog_submodule_templates(const ModuleManager& module_manager, print_one_verilog_template_module(module_manager, fp, circuit_lib.model_name(model)); } - /* Register the routing channel wires */ - for (const auto& seg : routing_segments) { - VTR_ASSERT( CircuitModelId::INVALID() != seg.circuit_model); - VTR_ASSERT( SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(seg.circuit_model)); - /* We care only user-defined circuit models */ - if (circuit_lib.model_verilog_netlist(seg.circuit_model).empty()) { - continue; - } - /* Give a unique name for subckt of wire_model of segment, - * circuit_model name is unique, and segment id is unique as well - */ - std::string segment_wire_subckt_name = generate_segment_wire_subckt_name(circuit_lib.model_name(seg.circuit_model), &seg - &routing_segments[0]); - /* Print a Verilog template for the circuit model */ - print_one_verilog_template_module(module_manager, fp, segment_wire_subckt_name); - } - /* close file stream */ fp.close(); @@ -3255,18 +3206,12 @@ void dump_verilog_submodules(ModuleManager& module_manager, t_det_routing_arch* routing_arch, t_syn_verilog_opts fpga_verilog_opts) { - /* Create a vector of segments. TODO: should come from DeviceContext */ - std::vector L_segment_vec; - for (int i = 0; i < Arch.num_segments; ++i) { - L_segment_vec.push_back(Arch.Segments[i]); - } - /* TODO: Register all the user-defined modules in the module manager * This should be done prior to other steps in this function, * because they will be instanciated by other primitive modules */ vpr_printf(TIO_MESSAGE_INFO, "Registering user-defined modules...\n"); - add_user_defined_verilog_modules(module_manager, Arch.spice->circuit_lib, L_segment_vec); + add_user_defined_verilog_modules(module_manager, Arch.spice->circuit_lib); print_verilog_submodule_essentials(module_manager, std::string(verilog_dir), @@ -3299,7 +3244,7 @@ void dump_verilog_submodules(ModuleManager& module_manager, fpga_verilog_opts.dump_explicit_verilog); /* 3. Hardwires */ - print_verilog_submodule_wires(module_manager, Arch.spice->circuit_lib, L_segment_vec, std::string(verilog_dir), std::string(submodule_dir)); + print_verilog_submodule_wires(module_manager, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir)); /* 4. Memories */ vpr_printf(TIO_MESSAGE_INFO, "Generating modules of memories...\n"); @@ -3311,7 +3256,7 @@ void dump_verilog_submodules(ModuleManager& module_manager, /* 5. Dump template for all the modules */ if (TRUE == fpga_verilog_opts.print_user_defined_template) { - print_verilog_submodule_templates(module_manager, Arch.spice->circuit_lib, L_segment_vec, std::string(verilog_dir), std::string(submodule_dir)); + print_verilog_submodule_templates(module_manager, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir)); } /* Create a header file to include all the subckts */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_wire.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_wire.cpp index b8b9443bc..1efe6d6cb 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_wire.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_wire.cpp @@ -90,92 +90,10 @@ void print_verilog_wire_module(ModuleManager& module_manager, } /******************************************************************** - * Print a Verilog module of a routing track wire segment - * Routing track wire, which is 1-input and dual output - * This type of wires are used in the global routing architecture. - * One of the output is wired to another Switch block multiplexer, - * while the mid-output is wired to a Connection block multiplexer. - * - * | CLB | - * +------------+ - * ^ - * | - * +------------------------------+ - * | Connection block multiplexer | - * +------------------------------+ - * ^ - * | mid-output +-------------- - * +--------------------+ | - * input --->| Routing track wire |--------->| Switch Block - * +--------------------+ output | - * +-------------- - * + * Top-level function to print wire modules *******************************************************************/ -static -void print_verilog_routing_wire_module(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - std::fstream& fp, - const CircuitModelId& wire_model, - const std::string& wire_subckt_name) { - /* Ensure a valid file handler*/ - check_file_handler(fp); - - /* Find the input port, output port*/ - std::vector input_ports = circuit_lib.model_ports_by_type(wire_model, SPICE_MODEL_PORT_INPUT, true); - std::vector output_ports = circuit_lib.model_ports_by_type(wire_model, SPICE_MODEL_PORT_OUTPUT, true); - - /* Make sure the port size is what we want */ - VTR_ASSERT (1 == input_ports.size()); - VTR_ASSERT (1 == output_ports.size()); - VTR_ASSERT (1 == circuit_lib.port_size(input_ports[0])); - VTR_ASSERT (1 == circuit_lib.port_size(output_ports[0])); - - /* Create a Verilog Module based on the circuit model, and add to module manager */ - ModuleId wire_module = module_manager.find_module(wire_subckt_name); - VTR_ASSERT(true == module_manager.valid_module_id(wire_module)); - - /* Add a mid-output port to the module */ - BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_lib_name(output_ports[0])), circuit_lib.port_size(output_ports[0])); - ModulePortId module_mid_output_port_id = module_manager.find_module_port(wire_module, module_mid_output_port.get_name()); - VTR_ASSERT(ModulePortId::INVALID() != module_mid_output_port_id); - - /* dump module definition + ports */ - print_verilog_module_declaration(fp, module_manager, wire_module); - /* Finish dumping ports */ - - /* Print the internal logic of Verilog module */ - /* Find the input port of the module */ - ModulePortId module_input_port_id = module_manager.find_module_port(wire_module, circuit_lib.port_lib_name(input_ports[0])); - VTR_ASSERT(ModulePortId::INVALID() != module_input_port_id); - BasicPort module_input_port = module_manager.module_port(wire_module, module_input_port_id); - - /* Find the output port of the module */ - ModulePortId module_output_port_id = module_manager.find_module_port(wire_module, circuit_lib.port_lib_name(output_ports[0])); - VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id); - BasicPort module_output_port = module_manager.module_port(wire_module, module_output_port_id); - - /* Print wire declaration for the inputs and outputs */ - fp << generate_verilog_port(VERILOG_PORT_WIRE, module_input_port) << ";" << std::endl; - fp << generate_verilog_port(VERILOG_PORT_WIRE, module_output_port) << ";" << std::endl; - fp << generate_verilog_port(VERILOG_PORT_WIRE, module_mid_output_port) << ";" << std::endl; - - /* Direct shortcut */ - print_verilog_wire_connection(fp, module_output_port, module_input_port, false); - print_verilog_wire_connection(fp, module_mid_output_port, module_input_port, false); - - /* Print timing info */ - print_verilog_submodule_timing(fp, circuit_lib, wire_model); - - /* Put an end to the Verilog module */ - print_verilog_module_end(fp, circuit_lib.model_name(wire_model)); - - /* Add an empty line as a splitter */ - fp << std::endl; -} - void print_verilog_submodule_wires(ModuleManager& module_manager, const CircuitLibrary& circuit_lib, - std::vector routing_segments, const std::string& verilog_dir, const std::string& submodule_dir) { std::string verilog_fname(submodule_dir + wires_verilog_file_name); @@ -205,26 +123,6 @@ void print_verilog_submodule_wires(ModuleManager& module_manager, print_verilog_wire_module(module_manager, circuit_lib, fp, model); } print_verilog_comment(fp, std::string("----- END Verilog modules for regular wires -----")); - - /* Create wire models for routing segments*/ - print_verilog_comment(fp, std::string("----- BEGIN Verilog modules for routing track wires -----")); - - for (const auto& seg : routing_segments) { - VTR_ASSERT( CircuitModelId::INVALID() != seg.circuit_model); - VTR_ASSERT( SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(seg.circuit_model)); - /* Bypass user-defined circuit models */ - if (!circuit_lib.model_verilog_netlist(seg.circuit_model).empty()) { - continue; - } - /* Give a unique name for subckt of wire_model of segment, - * circuit_model name is unique, and segment id is unique as well - */ - std::string segment_wire_subckt_name = generate_segment_wire_subckt_name(circuit_lib.model_name(seg.circuit_model), &seg - &routing_segments[0]); - - /* Print a Verilog module */ - print_verilog_routing_wire_module(module_manager, circuit_lib, fp, seg.circuit_model, segment_wire_subckt_name); - } - print_verilog_comment(fp, std::string("----- END Verilog modules for routing track wires -----")); /* Close the file stream */ fp.close(); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_wire.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_wire.h index 1d4fc7c71..e45cf483a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_wire.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_wire.h @@ -16,7 +16,6 @@ void print_verilog_submodule_wires(ModuleManager& module_manager, const CircuitLibrary& circuit_lib, - std::vector routing_segments, const std::string& verilog_dir, const std::string& submodule_dir); From 7952d134b99192fc996b177e75ef01edfb227320 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 16:24:39 -0700 Subject: [PATCH 33/68] add tree-like mux test case to regression test --- .travis/script.sh | 3 + .../tasks/blif_vpr_flow/config/task.conf | 2 - .../tasks/tree_like_mux/config/task.conf | 59 +++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 openfpga_flow/tasks/tree_like_mux/config/task.conf diff --git a/.travis/script.sh b/.travis/script.sh index 7c5aab29b..33391d502 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -25,6 +25,9 @@ python3 openfpga_flow/scripts/run_fpga_task.py single_mode --debug --show_thread echo -e "Testing multi-mode architectures"; python3 openfpga_flow/scripts/run_fpga_task.py blif_vpr_flow --maxthreads 4 --debug --show_thread_logs +echo -e "Testing tree-like multiplexer architectures"; +python3 openfpga_flow/scripts/run_fpga_task.py tree_like_mux --maxthreads 4 --debug --show_thread_logs + echo -e "Testing compact routing techniques"; python3 openfpga_flow/scripts/run_fpga_task.py compact_routing --debug --show_thread_logs diff --git a/openfpga_flow/tasks/blif_vpr_flow/config/task.conf b/openfpga_flow/tasks/blif_vpr_flow/config/task.conf index 152fcd6be..67f291319 100644 --- a/openfpga_flow/tasks/blif_vpr_flow/config/task.conf +++ b/openfpga_flow/tasks/blif_vpr_flow/config/task.conf @@ -15,14 +15,12 @@ timeout_each_job = 20*60 fpga_flow=vpr_blif [ARCHITECTURES] -# arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml arch3=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml #arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml -#arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml [BENCHMARKS] bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.blif diff --git a/openfpga_flow/tasks/tree_like_mux/config/task.conf b/openfpga_flow/tasks/tree_like_mux/config/task.conf new file mode 100644 index 000000000..e98e69a14 --- /dev/null +++ b/openfpga_flow/tasks/tree_like_mux/config/task.conf @@ -0,0 +1,59 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = true +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=vpr_blif + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.blif + +[SYNTHESIS_PARAM] +bench0_top = test_modes +bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.act +bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.v +bench0_chan_width = 300 + +#[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH] +#fix_route_chan_width=300 +#vpr_fpga_verilog_include_icarus_simulator= +#vpr_fpga_verilog_formal_verification_top_netlist= +#vpr_fpga_verilog_include_timing= +#vpr_fpga_verilog_include_signal_init= +#vpr_fpga_verilog_print_autocheck_top_testbench= +#vpr_fpga_bitstream_generator= +#vpr_fpga_verilog_print_user_defined_template= +#vpr_fpga_verilog_print_report_timing_tcl= +#vpr_fpga_verilog_print_sdc_pnr= +#vpr_fpga_verilog_print_sdc_analysis= +##vpr_fpga_x2p_compact_routing_hierarchy= +#end_flow_with_test= + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +min_route_chan_width=1.3 +vpr_fpga_verilog_include_icarus_simulator= +vpr_fpga_verilog_formal_verification_top_netlist= +vpr_fpga_verilog_include_timing= +vpr_fpga_verilog_include_signal_init= +vpr_fpga_verilog_print_autocheck_top_testbench= +vpr_fpga_bitstream_generator= +vpr_fpga_verilog_print_user_defined_template= +vpr_fpga_verilog_print_report_timing_tcl= +vpr_fpga_verilog_print_sdc_pnr= +vpr_fpga_verilog_print_sdc_analysis= +vpr_fpga_verilog_explicit_mapping= +vpr_fpga_x2p_compact_routing_hierarchy= +end_flow_with_test= + From 00280b835ebee5c1dabc9b5ef05fdd5920461f32 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 16:31:42 -0700 Subject: [PATCH 34/68] reorganize regression tests --- .travis/script.sh | 5 +- .../tasks/blif_vpr_flow/config/task.conf | 64 ------------------- .../tasks/multi_mode/config/task.conf | 22 ++++--- .../tasks/tree_like_mux/config/task.conf | 59 ----------------- 4 files changed, 15 insertions(+), 135 deletions(-) delete mode 100644 openfpga_flow/tasks/blif_vpr_flow/config/task.conf delete mode 100644 openfpga_flow/tasks/tree_like_mux/config/task.conf diff --git a/.travis/script.sh b/.travis/script.sh index 33391d502..dc0f1f18a 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -23,10 +23,7 @@ python3 openfpga_flow/scripts/run_fpga_task.py single_mode --debug --show_thread #python3 openfpga_flow/scripts/run_fpga_task.py s298 echo -e "Testing multi-mode architectures"; -python3 openfpga_flow/scripts/run_fpga_task.py blif_vpr_flow --maxthreads 4 --debug --show_thread_logs - -echo -e "Testing tree-like multiplexer architectures"; -python3 openfpga_flow/scripts/run_fpga_task.py tree_like_mux --maxthreads 4 --debug --show_thread_logs +python3 openfpga_flow/scripts/run_fpga_task.py multi_mode --maxthreads 4 --debug --show_thread_logs echo -e "Testing compact routing techniques"; python3 openfpga_flow/scripts/run_fpga_task.py compact_routing --debug --show_thread_logs diff --git a/openfpga_flow/tasks/blif_vpr_flow/config/task.conf b/openfpga_flow/tasks/blif_vpr_flow/config/task.conf deleted file mode 100644 index 67f291319..000000000 --- a/openfpga_flow/tasks/blif_vpr_flow/config/task.conf +++ /dev/null @@ -1,64 +0,0 @@ -# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -# Configuration file for running experiments -# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs -# Each job execute fpga_flow script on combination of architecture & benchmark -# timeout_each_job is timeout for each job -# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = - -[GENERAL] -power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml -power_analysis = true -spice_output=false -verilog_output=true -timeout_each_job = 20*60 -fpga_flow=vpr_blif - -[ARCHITECTURES] -arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml -arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml -arch3=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml -arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml -arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml -#arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml - -[BENCHMARKS] -bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.blif - -[SYNTHESIS_PARAM] -bench0_top = test_modes -bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.act -bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.v -bench0_chan_width = 300 - -#[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH] -#fix_route_chan_width=300 -#vpr_fpga_verilog_include_icarus_simulator= -#vpr_fpga_verilog_formal_verification_top_netlist= -#vpr_fpga_verilog_include_timing= -#vpr_fpga_verilog_include_signal_init= -#vpr_fpga_verilog_print_autocheck_top_testbench= -#vpr_fpga_bitstream_generator= -#vpr_fpga_verilog_print_user_defined_template= -#vpr_fpga_verilog_print_report_timing_tcl= -#vpr_fpga_verilog_print_sdc_pnr= -#vpr_fpga_verilog_print_sdc_analysis= -##vpr_fpga_x2p_compact_routing_hierarchy= -#end_flow_with_test= - -[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] -min_route_chan_width=1.3 -vpr_fpga_verilog_include_icarus_simulator= -vpr_fpga_verilog_formal_verification_top_netlist= -vpr_fpga_verilog_include_timing= -vpr_fpga_verilog_include_signal_init= -vpr_fpga_verilog_print_autocheck_top_testbench= -vpr_fpga_bitstream_generator= -vpr_fpga_verilog_print_user_defined_template= -vpr_fpga_verilog_print_report_timing_tcl= -vpr_fpga_verilog_print_sdc_pnr= -vpr_fpga_verilog_print_sdc_analysis= -#vpr_fpga_verilog_explicit_mapping= -#vpr_fpga_x2p_compact_routing_hierarchy= -end_flow_with_test= - diff --git a/openfpga_flow/tasks/multi_mode/config/task.conf b/openfpga_flow/tasks/multi_mode/config/task.conf index 5157bb235..51ff24dbd 100644 --- a/openfpga_flow/tasks/multi_mode/config/task.conf +++ b/openfpga_flow/tasks/multi_mode/config/task.conf @@ -15,16 +15,21 @@ timeout_each_job = 20*60 fpga_flow=vpr_blif [ARCHITECTURES] -arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml +arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml +arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml +arch3=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml +arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml +arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml +arch6=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml [BENCHMARKS] -bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k4_N4/K4N4_test_modes.blif +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.blif [SYNTHESIS_PARAM] -bench0_top = K4n4_test -bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k4_N4/K4N4_test_modes.act -bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k4_N4/K4N4_test_modes.v -bench0_chan_width = 100 +bench0_top = test_modes +bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.act +bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.v +bench0_chan_width = 300 #[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH] #fix_route_chan_width=300 @@ -38,10 +43,10 @@ bench0_chan_width = 100 #vpr_fpga_verilog_print_report_timing_tcl= #vpr_fpga_verilog_print_sdc_pnr= #vpr_fpga_verilog_print_sdc_analysis= -#vpr_fpga_x2p_compact_routing_hierarchy= +##vpr_fpga_x2p_compact_routing_hierarchy= #end_flow_with_test= -[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH_0] +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] min_route_chan_width=1.3 vpr_fpga_verilog_include_icarus_simulator= vpr_fpga_verilog_formal_verification_top_netlist= @@ -56,3 +61,4 @@ vpr_fpga_verilog_print_sdc_analysis= #vpr_fpga_verilog_explicit_mapping= #vpr_fpga_x2p_compact_routing_hierarchy= end_flow_with_test= + diff --git a/openfpga_flow/tasks/tree_like_mux/config/task.conf b/openfpga_flow/tasks/tree_like_mux/config/task.conf deleted file mode 100644 index e98e69a14..000000000 --- a/openfpga_flow/tasks/tree_like_mux/config/task.conf +++ /dev/null @@ -1,59 +0,0 @@ -# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -# Configuration file for running experiments -# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs -# Each job execute fpga_flow script on combination of architecture & benchmark -# timeout_each_job is timeout for each job -# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = - -[GENERAL] -power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml -power_analysis = true -spice_output=false -verilog_output=true -timeout_each_job = 20*60 -fpga_flow=vpr_blif - -[ARCHITECTURES] -arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml - -[BENCHMARKS] -bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.blif - -[SYNTHESIS_PARAM] -bench0_top = test_modes -bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.act -bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.v -bench0_chan_width = 300 - -#[SCRIPT_PARAM_FIX_ROUTE_CHAN_WIDTH] -#fix_route_chan_width=300 -#vpr_fpga_verilog_include_icarus_simulator= -#vpr_fpga_verilog_formal_verification_top_netlist= -#vpr_fpga_verilog_include_timing= -#vpr_fpga_verilog_include_signal_init= -#vpr_fpga_verilog_print_autocheck_top_testbench= -#vpr_fpga_bitstream_generator= -#vpr_fpga_verilog_print_user_defined_template= -#vpr_fpga_verilog_print_report_timing_tcl= -#vpr_fpga_verilog_print_sdc_pnr= -#vpr_fpga_verilog_print_sdc_analysis= -##vpr_fpga_x2p_compact_routing_hierarchy= -#end_flow_with_test= - -[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] -min_route_chan_width=1.3 -vpr_fpga_verilog_include_icarus_simulator= -vpr_fpga_verilog_formal_verification_top_netlist= -vpr_fpga_verilog_include_timing= -vpr_fpga_verilog_include_signal_init= -vpr_fpga_verilog_print_autocheck_top_testbench= -vpr_fpga_bitstream_generator= -vpr_fpga_verilog_print_user_defined_template= -vpr_fpga_verilog_print_report_timing_tcl= -vpr_fpga_verilog_print_sdc_pnr= -vpr_fpga_verilog_print_sdc_analysis= -vpr_fpga_verilog_explicit_mapping= -vpr_fpga_x2p_compact_routing_hierarchy= -end_flow_with_test= - From aa56d950738cdf50f1b8977c44a8f9a12856f341 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 17:19:57 -0700 Subject: [PATCH 35/68] bug fixed for using standard cells --- .../module_builder/build_device_module.cpp | 10 +-- .../build_essential_modules.cpp | 13 ++-- .../module_builder/build_essential_modules.h | 3 +- .../module_builder/build_wire_modules.cpp | 65 +------------------ .../module_builder/build_wire_modules.h | 3 +- 5 files changed, 14 insertions(+), 80 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_device_module.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_device_module.cpp index 772ee8f57..24c0e8c7d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_device_module.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_device_module.cpp @@ -75,12 +75,6 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup, arch.sram_inf.verilog_sram_inf_orgz->spice_model); config_circuit_models_sram_port_to_default_sram_model(arch.spice->circuit_lib, sram_model); - /* Create a vector of segments. TODO: should come from DeviceContext */ - std::vector L_segment_vec; - for (int i = 0; i < arch.num_segments; ++i) { - L_segment_vec.push_back(arch.Segments[i]); - } - /* Add constant generator modules: VDD and GND */ build_constant_generator_modules(module_manager); @@ -88,7 +82,7 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup, * This should be done prior to other steps in this function, * because they will be instanciated by other primitive modules */ - build_user_defined_modules(module_manager, arch.spice->circuit_lib, L_segment_vec); + build_user_defined_modules(module_manager, arch.spice->circuit_lib); /* Build elmentary modules */ build_essential_modules(module_manager, arch.spice->circuit_lib); @@ -103,7 +97,7 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup, build_lut_modules(module_manager, arch.spice->circuit_lib); /* Build wire modules */ - build_wire_modules(module_manager, arch.spice->circuit_lib, L_segment_vec); + build_wire_modules(module_manager, arch.spice->circuit_lib); /* Build memory modules */ build_memory_modules(module_manager, mux_lib, arch.spice->circuit_lib, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp index 8ebe2ab0e..1769b9d31 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp @@ -155,6 +155,12 @@ void build_essential_modules(ModuleManager& module_manager, "Building essential (inverter/buffer/logic gate) modules..."); for (const auto& circuit_model : circuit_lib.models()) { + /* We only care about user-defined models */ + if ( (false == circuit_lib.model_verilog_netlist(circuit_model).empty()) + && (false == circuit_lib.model_spice_netlist(circuit_model).empty()) ) { + continue; + } + if (SPICE_MODEL_INVBUF == circuit_lib.model_type(circuit_model)) { build_invbuf_module(module_manager, circuit_lib, circuit_model); continue; @@ -184,8 +190,7 @@ void build_essential_modules(ModuleManager& module_manager, * to the module_manager ********************************************************************/ void build_user_defined_modules(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - const std::vector& routing_segments) { + const CircuitLibrary& circuit_lib) { /* Start time count */ clock_t t_start = clock(); @@ -196,7 +201,7 @@ void build_user_defined_modules(ModuleManager& module_manager, for (const auto& model : circuit_lib.models()) { /* We only care about user-defined models */ if ( (true == circuit_lib.model_verilog_netlist(model).empty()) - && (true == circuit_lib.model_verilog_netlist(model).empty()) ) { + && (true == circuit_lib.model_spice_netlist(model).empty()) ) { continue; } /* Skip Routing channel wire models because they need a different name. Do it later */ @@ -273,7 +278,7 @@ void rename_primitive_module_port_names(ModuleManager& module_manager, for (const CircuitModelId& model : circuit_lib.models()) { /* We only care about user-defined models */ if ( (true == circuit_lib.model_verilog_netlist(model).empty()) - && (true == circuit_lib.model_verilog_netlist(model).empty()) ) { + && (true == circuit_lib.model_spice_netlist(model).empty()) ) { continue; } /* Skip Routing channel wire models because they need a different name. Do it later */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.h b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.h index 417f265b6..703d8a285 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.h @@ -8,8 +8,7 @@ void build_essential_modules(ModuleManager& module_manager, const CircuitLibrary& circuit_lib); void build_user_defined_modules(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - const std::vector& routing_segments); + const CircuitLibrary& circuit_lib); void build_constant_generator_modules(ModuleManager& module_manager); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.cpp index 6a064fa37..fd7527b6d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.cpp @@ -52,51 +52,6 @@ void build_wire_module(ModuleManager& module_manager, add_circuit_model_to_module_manager(module_manager, circuit_lib, wire_model); } -/******************************************************************** - * Build module of a routing track wire segment - * Routing track wire, which is 1-input and dual output - * This type of wires are used in the global routing architecture. - * One of the output is wired to another Switch block multiplexer, - * while the mid-output is wired to a Connection block multiplexer. - * - * | CLB | - * +------------+ - * ^ - * | - * +------------------------------+ - * | Connection block multiplexer | - * +------------------------------+ - * ^ - * | mid-output +-------------- - * +--------------------+ | - * input --->| Routing track wire |--------->| Switch Block - * +--------------------+ output | - * +-------------- - * - *******************************************************************/ -static -void build_routing_wire_module(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - const CircuitModelId& wire_model, - const std::string& wire_subckt_name) { - /* Find the input port, output port*/ - std::vector input_ports = circuit_lib.model_ports_by_type(wire_model, SPICE_MODEL_PORT_INPUT, true); - std::vector output_ports = circuit_lib.model_ports_by_type(wire_model, SPICE_MODEL_PORT_OUTPUT, true); - - /* Make sure the port size is what we want */ - VTR_ASSERT (1 == input_ports.size()); - VTR_ASSERT (1 == output_ports.size()); - VTR_ASSERT (1 == circuit_lib.port_size(input_ports[0])); - VTR_ASSERT (1 == circuit_lib.port_size(output_ports[0])); - - /* Create a Verilog Module based on the circuit model, and add to module manager */ - ModuleId wire_module = add_circuit_model_to_module_manager(module_manager, circuit_lib, wire_model, wire_subckt_name); - - /* Add a mid-output port to the module */ - BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_prefix(output_ports[0])), circuit_lib.port_size(output_ports[0])); - module_manager.add_port(wire_module, module_mid_output_port, ModuleManager::MODULE_OUTPUT_PORT); -} - /******************************************************************** * This function will only create wire modules with a number of * ports that are defined by users. @@ -104,8 +59,7 @@ void build_routing_wire_module(ModuleManager& module_manager, * by Verilog/SPICE writers *******************************************************************/ void build_wire_modules(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - std::vector routing_segments) { + const CircuitLibrary& circuit_lib) { /* Start time count */ clock_t t_start = clock(); @@ -122,23 +76,6 @@ void build_wire_modules(ModuleManager& module_manager, build_wire_module(module_manager, circuit_lib, wire_model); } - for (const auto& seg : routing_segments) { - VTR_ASSERT( CircuitModelId::INVALID() != seg.circuit_model); - VTR_ASSERT( SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(seg.circuit_model)); - /* Bypass user-defined circuit models */ - if ( (!circuit_lib.model_spice_netlist(seg.circuit_model).empty()) - && (!circuit_lib.model_verilog_netlist(seg.circuit_model).empty()) ) { - continue; - } - /* Give a unique name for subckt of wire_model of segment, - * circuit_model name is unique, and segment id is unique as well - */ - std::string segment_wire_subckt_name = generate_segment_wire_subckt_name(circuit_lib.model_name(seg.circuit_model), &seg - &routing_segments[0]); - - /* Print a Verilog module */ - build_routing_wire_module(module_manager, circuit_lib, seg.circuit_model, segment_wire_subckt_name); - } - /* End time count */ clock_t t_end = clock(); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.h b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.h index a68eb22b0..193071526 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_wire_modules.h @@ -14,7 +14,6 @@ #include "module_manager.h" void build_wire_modules(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - std::vector routing_segments); + const CircuitLibrary& circuit_lib); #endif From 227fb9a1a573d806f981d4cd0a6a4ffdf41fc994 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 17:32:05 -0700 Subject: [PATCH 36/68] clean up the support for std cells --- .../SRC/fpga_x2p/module_builder/build_essential_modules.cpp | 6 +++--- .../fpga_x2p/module_builder/build_module_graph_utils.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp index 1769b9d31..9bb471710 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_essential_modules.cpp @@ -155,9 +155,9 @@ void build_essential_modules(ModuleManager& module_manager, "Building essential (inverter/buffer/logic gate) modules..."); for (const auto& circuit_model : circuit_lib.models()) { - /* We only care about user-defined models */ - if ( (false == circuit_lib.model_verilog_netlist(circuit_model).empty()) - && (false == circuit_lib.model_spice_netlist(circuit_model).empty()) ) { + /* Add essential modules upon on demand: only when it is not yet in the module library */ + ModuleId module = module_manager.find_module(circuit_lib.model_name(circuit_model)); + if (true == module_manager.valid_module_id(module)) { continue; } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.cpp index 241b5f631..fc710a20d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.cpp @@ -28,7 +28,7 @@ ModulePortId find_inverter_buffer_module_port(const ModuleManager& module_manage VTR_ASSERT(1 == model_ports.size()); /* Find the input and output module ports */ - ModulePortId module_port_id = module_manager.find_module_port(module_id, circuit_lib.port_lib_name(model_ports[0])); + ModulePortId module_port_id = module_manager.find_module_port(module_id, circuit_lib.port_prefix(model_ports[0])); VTR_ASSERT(true == module_manager.valid_module_port_id(module_id, module_port_id)); return module_port_id; From 066962fbb99a8405003f8b92e59308d61fd4c3c6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 17:41:21 -0700 Subject: [PATCH 37/68] bug fixed for clb2clb direct connection --- .../SRC/fpga_x2p/module_builder/build_top_module_directs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_directs.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_directs.cpp index dafce007b..6179e4d4c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_directs.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_directs.cpp @@ -102,7 +102,7 @@ void add_module_nets_clb2clb_direct_connection(ModuleManager& module_manager, VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_output_port_id)); VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_output_port_id).get_width()); - for (size_t pin_id : src_clb_port.pins()) { + for (size_t pin_id = 0; pin_id < src_clb_port.pins().size(); ++pin_id) { /* Generate the pin name of source port/pin in the grid */ size_t src_pin_height = find_grid_pin_height(grids, src_clb_coord, src_clb_port.pins()[pin_id]); e_side src_pin_grid_side = find_grid_pin_side(device_size, grids, src_clb_coord, src_pin_height, src_clb_port.pins()[pin_id]); From 6c04b8d9591e8371101d892e020c764774bbe580 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 5 Nov 2019 20:24:03 -0700 Subject: [PATCH 38/68] bug fixing for heterogeneous FPGAs --- .../vpr/SRC/fpga_x2p/module_builder/build_top_module.cpp | 8 ++++---- vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module.cpp index a8a5d66e9..683b5138d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module.cpp @@ -684,16 +684,16 @@ void add_top_module_nets_connect_sb_and_cb(ModuleManager& module_manager, * FOr RIGHT and BOTTOM side, find the adjacent RRGSB and then use is_cb_exist() */ if ( TOP == side_manager.get_side() || LEFT == side_manager.get_side() ) { - if ( (TRUE != is_cb_exist(cb_type, module_gsb_cb_coordinate.get_x(), module_gsb_cb_coordinate.get_y())) + if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type))) || (true != rr_gsb.is_cb_exist(cb_type))) { continue; } } if ( RIGHT == side_manager.get_side() || BOTTOM == side_manager.get_side() ) { - const RRGSB& adjancent_gsb = L_device_rr_gsb.get_gsb(module_gsb_cb_coordinate); - if ( (TRUE != is_cb_exist(cb_type, module_gsb_cb_coordinate.get_x(), module_gsb_cb_coordinate.get_y())) - || (true != adjancent_gsb.is_cb_exist(cb_type))) { + const RRGSB& adjacent_gsb = L_device_rr_gsb.get_gsb(module_gsb_cb_coordinate); + if ( (TRUE != is_cb_exist(cb_type, adjacent_gsb.get_cb_x(cb_type), adjacent_gsb.get_cb_y(cb_type))) + || (true != adjacent_gsb.is_cb_exist(cb_type))) { continue; } } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c index 2c995e864..12afb3a2e 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c @@ -4064,7 +4064,7 @@ void print_verilog_flatten_connection_block_modules(ModuleManager& module_manage * We will skip those modules */ const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); - if ( (TRUE != is_cb_exist(CHANX, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type))) + if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type))) || (true != rr_gsb.is_cb_exist(cb_type))) { continue; } From aac4ccb279395c6bc7af94d5e7980eba5d7855aa Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 6 Nov 2019 11:19:17 -0700 Subject: [PATCH 39/68] fixing bug for heterogeneous FPGAs --- .../fpga_x2p/base/fpga_x2p_unique_routing.c | 16 ++++++++++++++ .../vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp | 21 +++++++++++++++++++ .../vpr/SRC/fpga_x2p/base/rr_blocks_utils.h | 3 +++ .../bitstream/build_routing_bitstream.cpp | 8 +++++-- .../module_builder/build_routing_modules.cpp | 3 +-- .../module_builder/build_top_module.cpp | 19 +++++++++-------- .../build_top_module_memory.cpp | 9 ++++++-- .../SRC/fpga_x2p/verilog/verilog_tcl_utils.c | 11 ++++++++-- 8 files changed, 73 insertions(+), 17 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.c index 4385cd5f7..e8ac5a4e4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.c @@ -1119,6 +1119,22 @@ RRGSB build_rr_gsb(DeviceCoordinator& device_range, if (0 == rr_gsb.get_chan_width(chan_side)) { continue; } + /* For bottom side: Skip IPIN collection if the offset of the grid is not zero! + * (it means this CB is in the middle of a grid (whose height > 1) + * + * | | | | + * | | | | + * | Grid | | Grid | + * +------------+ | | + * IPIN nodes IPIN nodes + * exist do NOT exist + */ + if ((BOTTOM == ipin_rr_node_grid_side) && (0 < grid[ix][iy].offset)) { + continue; + } + if ((TOP == ipin_rr_node_grid_side) && (grid[ix][iy].offset != grid[ix][iy].type->height - 1)) { + continue; + } /* Collect IPIN rr_nodes*/ temp_ipin_rr_node = get_grid_side_pin_rr_nodes(&(num_temp_ipin_rr_nodes), IPIN, ix, iy, ipin_rr_node_grid_side, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp index 9cd735aeb..4066c3a63 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.cpp @@ -334,4 +334,25 @@ size_t find_switch_block_num_shared_conf_bits(t_sram_orgz_info* cur_sram_orgz_in return num_shared_conf_bits; } +/******************************************************************** + * Find if a X-direction or Y-direction Connection Block contains + * routing tracks only (zero configuration bits and routing multiplexers) + *******************************************************************/ +bool connection_block_contain_only_routing_tracks(const RRGSB& rr_gsb, + const t_rr_type& cb_type) { + bool routing_track_only = true; + /* Find routing multiplexers on the sides of a Connection block where IPIN nodes locate */ + std::vector cb_sides = rr_gsb.get_cb_ipin_sides(cb_type); + + for (size_t side = 0; side < cb_sides.size(); ++side) { + enum e_side cb_ipin_side = cb_sides[side]; + Side side_manager(cb_ipin_side); + if (0 < rr_gsb.get_num_ipin_nodes(cb_ipin_side)) { + routing_track_only = false; + break; + } + } + + return routing_track_only; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h index 711517a0c..59e8639ad 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks_utils.h @@ -51,4 +51,7 @@ size_t find_switch_block_num_shared_conf_bits(t_sram_orgz_info* cur_sram_orgz_in const std::vector& rr_switches, const RRGSB& rr_gsb); +bool connection_block_contain_only_routing_tracks(const RRGSB& rr_gsb, + const t_rr_type& cb_type); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/build_routing_bitstream.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/build_routing_bitstream.cpp index c650d7704..5d2c558ad 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/build_routing_bitstream.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/build_routing_bitstream.cpp @@ -10,6 +10,7 @@ #include "vtr_assert.h" #include "util.h" #include "mux_utils.h" +#include "rr_blocks_utils.h" #include "fpga_x2p_reserved_words.h" #include "fpga_x2p_types.h" #include "fpga_x2p_naming.h" @@ -318,8 +319,11 @@ void build_connection_block_bitstreams(BitstreamManager& bitstream_manager, * Some of them do NOT exist due to heterogeneous blocks (height > 1) * We will skip those modules */ - if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type))) - || (true != rr_gsb.is_cb_exist(cb_type))) { + if (false == rr_gsb.is_cb_exist(cb_type)) { + continue; + } + /* Skip if the cb does not contain any configuration bits! */ + if (true == connection_block_contain_only_routing_tracks(rr_gsb, cb_type)) { continue; } /* Create a block for the bitstream which corresponds to the Switch block */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp index 04842a5cc..35fd4a296 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp @@ -1044,8 +1044,7 @@ void build_flatten_connection_block_modules(ModuleManager& module_manager, * We will skip those modules */ const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); - if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type))) - || (true != rr_gsb.is_cb_exist(cb_type))) { + if (false == rr_gsb.is_cb_exist(cb_type)) { continue; } build_connection_block_module(module_manager, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module.cpp index 683b5138d..a8e3543e5 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module.cpp @@ -11,6 +11,7 @@ #include "vpr_types.h" #include "globals.h" +#include "rr_blocks_utils.h" #include "fpga_x2p_reserved_words.h" #include "fpga_x2p_naming.h" #include "fpga_x2p_utils.h" @@ -311,9 +312,7 @@ std::vector> add_top_module_connection_block_instances(Modul */ const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); vtr::Point cb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); - const DeviceCoordinator cb_coordinator = rr_gsb.get_cb_coordinator(cb_type); - if ( (TRUE != is_cb_exist(cb_type, cb_coordinator.get_x(), cb_coordinator.get_y())) - || (true != rr_gsb.is_cb_exist(cb_type))) { + if ( false == rr_gsb.is_cb_exist(cb_type) ) { continue; } /* If we use compact routing hierarchy, we should instanciate the unique module of SB */ @@ -522,8 +521,12 @@ void add_top_module_nets_connect_grids_and_cb(ModuleManager& module_manager, DeviceCoordinator module_gsb_coordinate(rr_gsb.get_x(), rr_gsb.get_y()); /* Skip those Connection blocks that do not exist */ - if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type))) - || (true != rr_gsb.is_cb_exist(cb_type))) { + if (false == rr_gsb.is_cb_exist(cb_type)) { + return; + } + + /* Skip if the cb does not contain any configuration bits! */ + if (true == connection_block_contain_only_routing_tracks(rr_gsb, cb_type)) { return; } @@ -684,16 +687,14 @@ void add_top_module_nets_connect_sb_and_cb(ModuleManager& module_manager, * FOr RIGHT and BOTTOM side, find the adjacent RRGSB and then use is_cb_exist() */ if ( TOP == side_manager.get_side() || LEFT == side_manager.get_side() ) { - if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type))) - || (true != rr_gsb.is_cb_exist(cb_type))) { + if ( false == rr_gsb.is_cb_exist(cb_type)) { continue; } } if ( RIGHT == side_manager.get_side() || BOTTOM == side_manager.get_side() ) { const RRGSB& adjacent_gsb = L_device_rr_gsb.get_gsb(module_gsb_cb_coordinate); - if ( (TRUE != is_cb_exist(cb_type, adjacent_gsb.get_cb_x(cb_type), adjacent_gsb.get_cb_y(cb_type))) - || (true != adjacent_gsb.is_cb_exist(cb_type))) { + if ( false == adjacent_gsb.is_cb_exist(cb_type)) { continue; } } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_memory.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_memory.cpp index e795ab7ad..4042febd7 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_memory.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_top_module_memory.cpp @@ -4,6 +4,7 @@ *******************************************************************/ #include "vtr_assert.h" +#include "rr_blocks_utils.h" #include "fpga_x2p_utils.h" #include "fpga_x2p_naming.h" @@ -31,8 +32,12 @@ void organize_top_module_tile_cb_modules(ModuleManager& module_manager, const t_rr_type& cb_type, const bool& compact_routing_hierarchy) { /* If the CB does not exist, we can skip addition */ - if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type))) - || (true != rr_gsb.is_cb_exist(cb_type))) { + if ( false == rr_gsb.is_cb_exist(cb_type)) { + return; + } + + /* Skip if the cb does not contain any configuration bits! */ + if (true == connection_block_contain_only_routing_tracks(rr_gsb, cb_type)) { return; } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.c index c3df4ed95..7fa1b51e6 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_tcl_utils.c @@ -354,8 +354,11 @@ t_cb* get_chan_rr_node_ending_cb(t_rr_node* src_rr_node, */ assert (src_rr_node->xlow == src_rr_node->xhigh); next_cb_x = src_rr_node->xlow; - assert (end_rr_node->ylow == end_rr_node->yhigh); - next_cb_y = end_rr_node->ylow; + /* Heterogeneous blocks may have ylow != yhigh */ + if (IPIN != end_rr_node->type) { + assert (end_rr_node->ylow == end_rr_node->yhigh); + } + next_cb_y = end_rr_node->yhigh; /* Side will be either on RIGHT or LEFT */ ipin_side[0] = LEFT; ipin_side[1] = RIGHT; @@ -372,6 +375,7 @@ t_cb* get_chan_rr_node_ending_cb(t_rr_node* src_rr_node, } /* Double check if src_rr_node is in the IN_PORT list */ + /* TODO: this part should be refactored! node_exist = 0; for (iside = 0; iside < num_chan_sides; iside++) { if (OPEN != get_rr_node_index_in_cb_info( src_rr_node, @@ -381,8 +385,10 @@ t_cb* get_chan_rr_node_ending_cb(t_rr_node* src_rr_node, } } assert (0 < node_exist); + */ /* Double check if end_rr_node is in the OUT_PORT list */ + /* TODO: this part should be refactored! node_exist = 0; for (iside = 0; iside < num_ipin_sides; iside++) { if (OPEN != get_rr_node_index_in_cb_info( end_rr_node, @@ -392,6 +398,7 @@ t_cb* get_chan_rr_node_ending_cb(t_rr_node* src_rr_node, } } assert (0 < node_exist); + */ return next_cb; } From 0e620f35a4eff1237a9ba64acb51bbf93a94d4f0 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 6 Nov 2019 11:45:28 -0700 Subject: [PATCH 40/68] bug fixed for MUX2 std cells, avoid duplicated module writing --- vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp index 06c2e1f4c..69eea6452 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp @@ -582,6 +582,13 @@ void generate_verilog_mux_branch_module(ModuleManager& module_manager, /* Multiplexers built with different technology is in different organization */ switch (circuit_lib.design_tech_type(mux_model)) { case SPICE_MODEL_DESIGN_CMOS: + /* Skip module writing if the branch subckt is a standard cell! */ + if (true == circuit_lib.valid_model_id(circuit_lib.model(module_name))) { + /* This model must be a MUX2 gate */ + VTR_ASSERT(SPICE_MODEL_GATE == circuit_lib.model_type(circuit_lib.model(module_name))); + VTR_ASSERT(SPICE_MODEL_GATE_MUX2 == circuit_lib.gate_type(circuit_lib.model(module_name))); + break; + } if (true == circuit_lib.dump_structural_verilog(mux_model)) { /* Structural verilog can be easily generated by module writer */ ModuleId mux_module = module_manager.find_module(module_name); From 09eb373a6e20dd99304d248c696ee7505fcf6c4a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 6 Nov 2019 12:21:20 -0700 Subject: [PATCH 41/68] bug fixing for autocheck top testbench where clock port is not default names --- openfpga_flow/VerilogNetlists/dpram_32x1024.v | 56 +++++++++++++++++++ .../verilog/verilog_top_testbench.cpp | 36 ++++++++++-- 2 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 openfpga_flow/VerilogNetlists/dpram_32x1024.v diff --git a/openfpga_flow/VerilogNetlists/dpram_32x1024.v b/openfpga_flow/VerilogNetlists/dpram_32x1024.v new file mode 100644 index 000000000..404548a95 --- /dev/null +++ b/openfpga_flow/VerilogNetlists/dpram_32x1024.v @@ -0,0 +1,56 @@ +//----------------------------------------------------- +// Design Name : dual_port_ram_32x1024 +// File Name : dpram_32x1024.v +// Function : Dual port RAM 32x1024 +// Coder : Aurelien Alacchi +//----------------------------------------------------- + +module dual_port_ram_32x1024 ( + input clk, + input wen, + input ren, + input[0:9] waddr, + input[0:9] raddr, + input[0:31] d_in, + output[0:31] d_out ); + + dual_port_sram_32x1024 memory_0 ( + .wclk (clk), + .wen (wen), + .waddr (waddr), + .data_in (d_in), + .rclk (clk), + .ren (ren), + .raddr (raddr), + .d_out (d_out) ); + +endmodule + +module dual_port_sram_32x1024 ( + input wclk, + input wen, + input[0:9] waddr, + input[0:31] data_in, + input rclk, + input ren, + input[0:9] raddr, + output[0:31] d_out ); + + reg[0:31] ram[0:1023]; + reg[0:31] internal; + + assign d_out = internal; + + always @(negedge wclk) begin + if(wen) begin + ram[waddr] <= data_in; + end + end + + always @(negedge rclk) begin + if(ren) begin + internal <= ram[raddr]; + end + end + +endmodule diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp index 4fcebf6c4..9f801c44a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_testbench.cpp @@ -289,6 +289,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp, const ModuleManager& module_manager, const ModuleId& top_module, const std::vector& L_logical_blocks, + const std::vector& clock_port_names, const e_sram_orgz& sram_orgz_type, const std::string& circuit_name){ /* Validate the file stream */ @@ -353,6 +354,31 @@ void print_verilog_top_testbench_ports(std::fstream& fp, /* Configuration ports depend on the organization of SRAMs */ print_verilog_top_testbench_config_protocol_port(fp, sram_orgz_type); + /* Create a clock port if the benchmark have one but not in the default name! + * We will wire the clock directly to the operating clock directly + */ + for (const std::string clock_port_name : clock_port_names) { + if (0 == clock_port_name.compare(op_clock_port.get_name())) { + continue; + } + /* Ensure the clock port name is not a duplication of global ports of the FPGA module */ + bool print_clock_port = true; + for (const BasicPort& module_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GLOBAL_PORT)) { + if (0 == clock_port_name.compare(module_port.get_name())) { + print_clock_port = false; + } + } + if (false == print_clock_port) { + continue; + } + + /* Print the clock and wire it to op_clock */ + print_verilog_comment(fp, std::string("----- Create a clock for benchmark and wire it to op_clock -------")); + BasicPort clock_port(clock_port_name, 1); + fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, clock_port) << ";" << std::endl; + print_verilog_wire_connection(fp, clock_port, op_clock_port, false); + } + print_verilog_testbench_shared_ports(fp, L_logical_blocks, std::string(TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX), std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX), @@ -753,9 +779,12 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name()); VTR_ASSERT(true == module_manager.valid_module_id(top_module)); + /* Preparation: find all the clock ports */ + std::vector clock_port_names = find_benchmark_clock_port_name(L_logical_blocks); + /* Start of testbench */ - //dump_verilog_top_auto_testbench_ports(fp, cur_sram_orgz_info, circuit_name, fpga_verilog_opts); - print_verilog_top_testbench_ports(fp, module_manager, top_module, L_logical_blocks, + print_verilog_top_testbench_ports(fp, module_manager, top_module, + L_logical_blocks, clock_port_names, sram_orgz_type, circuit_name); /* Find the clock period */ @@ -803,9 +832,6 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, print_verilog_top_testbench_bitstream(fp, sram_orgz_type, bitstream_manager, fabric_bitstream); - /* Preparation: find all the clock ports */ - std::vector clock_port_names = find_benchmark_clock_port_name(L_logical_blocks); - /* Add stimuli for reset, set, clock and iopad signals */ print_verilog_testbench_random_stimuli(fp, L_logical_blocks, std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX), From 4ea5756be6a2366da98f2eb98b925a853d410e56 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 6 Nov 2019 16:06:47 -0700 Subject: [PATCH 42/68] bug fixed for std cell MUX2 architecture and add the case to regression tests --- openfpga_flow/VerilogNetlists/mux2.v | 53 + ...10_sram_chain_HC_stdcell_mux2_template.xml | 1030 +++++++++++++++++ .../tasks/multi_mode/config/task.conf | 13 +- .../vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp | 5 +- 4 files changed, 1094 insertions(+), 7 deletions(-) create mode 100644 openfpga_flow/VerilogNetlists/mux2.v create mode 100644 openfpga_flow/arch/template/k6_N10_sram_chain_HC_stdcell_mux2_template.xml diff --git a/openfpga_flow/VerilogNetlists/mux2.v b/openfpga_flow/VerilogNetlists/mux2.v new file mode 100644 index 000000000..b539b7a69 --- /dev/null +++ b/openfpga_flow/VerilogNetlists/mux2.v @@ -0,0 +1,53 @@ +//----------------------------------------------------- +// Design Name : MUX2 +// File Name : mux2.v +// Function : Standard cell (static gate) implementation +// of 2-input multiplexers +// Coder : Xifan Tang +//----------------------------------------------------- + +module MUX2( + input A, // Data input 0 + input B, // Data input 1 + input S0, // Select port + output Y // Data output + ); + + assign Y = S0 ? B : A; + +// Note: +// MUX2 appears will appear in LUTs, routing multiplexers, +// being a component in combinational loops +// To help convergence in simulation +// i.e., to avoid the X (undetermined) signals, +// the following timing constraints and signal initialization +// has to be added! + +`ifdef ENABLE_TIMING +// ------ BEGIN Pin-to-pin Timing constraints ----- + specify + (A => Y) = (0.001, 0.001); + (B => Y) = (0.001, 0.001); + (S0 => Y) = (0.001, 0.001); + endspecify +// ------ END Pin-to-pin Timing constraints ----- +`endif + +`ifdef ENABLE_SIGNAL_INITIALIZATION +// ------ BEGIN driver initialization ----- + initial begin + `ifdef ENABLE_FORMAL_VERIFICATION + $deposit(A, 1'b0); + $deposit(B, 1'b0); + $deposit(S0, 1'b0); + `else + $deposit(A, $random); + $deposit(B, $random); + $deposit(S0, $random); + `endif + + end +// ------ END driver initialization ----- +`endif + +endmodule diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_stdcell_mux2_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_stdcell_mux2_template.xml new file mode 100644 index 000000000..410edebcf --- /dev/null +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_stdcell_mux2_template.xml @@ -0,0 +1,1030 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + + + + 10e-12 5e-12 5e-12 + + + 10e-12 5e-12 5e-12 + + + + + + + + + + + + + + + + + + + + 10e-12 10e-12 + + + 10e-12 10e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + + + + 1 1 1 1 1 + 1 1 1 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + io.outpad io.inpad + io.outpad io.inpad + io.outpad io.inpad + io.outpad io.inpad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 255e-12 + 255e-12 + 255e-12 + 255e-12 + 255e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 202e-12 + 202e-12 + 202e-12 + 202e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + clb.cin clb.cin_trick clb.regin clb.clk + clb.I0[9:0] clb.I1[9:0] clb.O[9:0] + clb.cout clb.regout clb.I2[9:0] clb.I3[9:0] clb.O[19:10] + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/multi_mode/config/task.conf b/openfpga_flow/tasks/multi_mode/config/task.conf index 51ff24dbd..18f471cf7 100644 --- a/openfpga_flow/tasks/multi_mode/config/task.conf +++ b/openfpga_flow/tasks/multi_mode/config/task.conf @@ -15,12 +15,13 @@ timeout_each_job = 20*60 fpga_flow=vpr_blif [ARCHITECTURES] -arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml -arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml -arch3=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml -arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml -arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml -arch6=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml +arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml +arch2=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_behavioral_verilog_template.xml +arch3=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_non_lut_intermediate_buffer_template.xml +arch4=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_1IO_template.xml +arch5=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_tree_mux_template.xml +arch6=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_stdcell_mux2_template.xml [BENCHMARKS] bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/test_modes/k6_N10/K6N10_test_modes.blif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp index 69eea6452..a52018ff3 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_mux.cpp @@ -1192,7 +1192,10 @@ void generate_verilog_mux_module(ModuleManager& module_manager, ModuleId mux_module = module_manager.find_module(module_name); VTR_ASSERT(true == module_manager.valid_module_id(mux_module)); write_verilog_module_to_file(fp, module_manager, mux_module, - use_explicit_port_map || circuit_lib.dump_explicit_port_map(mux_model)); + ( use_explicit_port_map + || circuit_lib.dump_explicit_port_map(mux_model) + || circuit_lib.dump_explicit_port_map(circuit_lib.pass_gate_logic_model(mux_model)) ) + ); /* Add an empty line as a splitter */ fp << std::endl; break; From 56b4ee008e2a57b00aa6986a125960247af66f80 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 6 Nov 2019 17:45:11 -0700 Subject: [PATCH 43/68] add test for heterogeneous FPGA and fix bugs --- .../{dpram_32x1024.v => dpram.v} | 0 .../k6_N10_sram_chain_HC_DPRAM_template.xml | 32 ++--- .../pipelined_8bit_adder.act | 95 +++++++++++++ .../pipelined_8bit_adder.blif | 126 ++++++++++++++++++ .../pipelined_8bit_adder.v | 99 ++++++++++++++ .../heterogeneous_dpram/config/task.conf | 43 ++++++ .../base/fpga_x2p_backannotate_utils.c | 4 + 7 files changed, 383 insertions(+), 16 deletions(-) rename openfpga_flow/VerilogNetlists/{dpram_32x1024.v => dpram.v} (100%) create mode 100644 openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.act create mode 100644 openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.blif create mode 100644 openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.v create mode 100644 openfpga_flow/tasks/heterogeneous_dpram/config/task.conf diff --git a/openfpga_flow/VerilogNetlists/dpram_32x1024.v b/openfpga_flow/VerilogNetlists/dpram.v similarity index 100% rename from openfpga_flow/VerilogNetlists/dpram_32x1024.v rename to openfpga_flow/VerilogNetlists/dpram.v diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml index 10cd18ddd..103152e31 100644 --- a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml @@ -146,7 +146,7 @@ - + @@ -163,8 +163,8 @@ - - + + @@ -344,14 +344,14 @@ - + - - + + @@ -386,17 +386,17 @@ - + - + - + @@ -421,7 +421,7 @@ - + @@ -613,7 +613,7 @@ - + @@ -631,7 +631,7 @@ - + @@ -674,13 +674,13 @@ - - + memory_dp.d_in - memory_dp.clk memory_dp.wen memory_dp.waddr + memory_dp.clk memory_dp.wen memory_dp.waddr memory_dp.d_out memory_dp.ren memory_dp.raddr - + diff --git a/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.act b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.act new file mode 100644 index 000000000..d8c59ec70 --- /dev/null +++ b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.act @@ -0,0 +1,95 @@ +clk 0.5 0.2 +wen 0.5 0.2 +wen_st0 0.5 0.2 +wen_st1 0.5 0.2 +ren 0.5 0.2 +raddr_0_ 0.5 0.2 +raddr_1_ 0.5 0.2 +raddr_2_ 0.5 0.2 +raddr_3_ 0.5 0.2 +raddr_4_ 0.5 0.2 +raddr_5_ 0.5 0.2 +waddr_0_ 0.5 0.2 +waddr_1_ 0.5 0.2 +waddr_2_ 0.5 0.2 +waddr_3_ 0.5 0.2 +waddr_4_ 0.5 0.2 +waddr_5_ 0.5 0.2 +waddr_st0_0_ 0.5 0.2 +waddr_st0_1_ 0.5 0.2 +waddr_st0_2_ 0.5 0.2 +waddr_st0_3_ 0.5 0.2 +waddr_st0_4_ 0.5 0.2 +waddr_st0_5_ 0.5 0.2 +waddr_st1_0_ 0.5 0.2 +waddr_st1_1_ 0.5 0.2 +waddr_st1_2_ 0.5 0.2 +waddr_st1_3_ 0.5 0.2 +waddr_st1_4_ 0.5 0.2 +waddr_st1_5_ 0.5 0.2 +a_0_ 0.5 0.2 +a_1_ 0.5 0.2 +a_2_ 0.5 0.2 +a_3_ 0.5 0.2 +a_4_ 0.5 0.2 +a_5_ 0.5 0.2 +a_6_ 0.5 0.2 +a_st0_0_ 0.5 0.2 +a_st0_1_ 0.5 0.2 +a_st0_2_ 0.5 0.2 +a_st0_3_ 0.5 0.2 +a_st0_4_ 0.5 0.2 +a_st0_5_ 0.5 0.2 +a_st0_6_ 0.5 0.2 +a_st1_0_ 0.5 0.2 +a_st1_1_ 0.5 0.2 +a_st1_2_ 0.5 0.2 +a_st1_3_ 0.5 0.2 +a_st1_4_ 0.5 0.2 +a_st1_5_ 0.5 0.2 +a_st1_6_ 0.5 0.2 +b_0_ 0.5 0.2 +b_1_ 0.5 0.2 +b_2_ 0.5 0.2 +b_3_ 0.5 0.2 +b_4_ 0.5 0.2 +b_5_ 0.5 0.2 +b_6_ 0.5 0.2 +b_st0_0_ 0.5 0.2 +b_st0_1_ 0.5 0.2 +b_st0_2_ 0.5 0.2 +b_st0_3_ 0.5 0.2 +b_st0_4_ 0.5 0.2 +b_st0_5_ 0.5 0.2 +b_st0_6_ 0.5 0.2 +b_st1_0_ 0.5 0.2 +b_st1_1_ 0.5 0.2 +b_st1_2_ 0.5 0.2 +b_st1_3_ 0.5 0.2 +b_st1_4_ 0.5 0.2 +b_st1_5_ 0.5 0.2 +b_st1_6_ 0.5 0.2 +q_0_ 0.5 0.2 +q_1_ 0.5 0.2 +q_2_ 0.5 0.2 +q_3_ 0.5 0.2 +q_4_ 0.5 0.2 +q_5_ 0.5 0.2 +q_6_ 0.5 0.2 +q_7_ 0.5 0.2 +AplusB_0_ 0.5 0.2 +AplusB_1_ 0.5 0.2 +AplusB_2_ 0.5 0.2 +AplusB_3_ 0.5 0.2 +AplusB_4_ 0.5 0.2 +AplusB_5_ 0.5 0.2 +AplusB_6_ 0.5 0.2 +AplusB_7_ 0.5 0.2 +cint01 0.5 0.2 +cint02 0.5 0.2 +cint03 0.5 0.2 +cint04 0.5 0.2 +cint05 0.5 0.2 +cint06 0.5 0.2 +cint07 0.5 0.2 +zero00 0 0 diff --git a/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.blif b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.blif new file mode 100644 index 000000000..4ec6b2a99 --- /dev/null +++ b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.blif @@ -0,0 +1,126 @@ +# Benchmark pipelined_32b_adder +.model pipelined_32b_adder +.inputs clk wen ren raddr_0_ raddr_1_ raddr_2_ raddr_3_ raddr_4_ raddr_5_ waddr_0_ waddr_1_ waddr_2_ waddr_3_ waddr_4_ waddr_5_ a_0_ a_1_ a_2_ a_3_ a_4_ a_5_ a_6_ b_0_ b_1_ b_2_ b_3_ b_4_ b_5_ b_6_ +.outputs q_0_ q_1_ q_2_ q_3_ q_4_ q_5_ q_6_ q_7_ + +# Start pipeline +# Pipeline a +.subckt shift D=a_0_ clk=clk Q=a_st0_0_ +.subckt shift D=a_st0_0_ clk=clk Q=a_st1_0_ +.subckt shift D=a_1_ clk=clk Q=a_st0_1_ +.subckt shift D=a_st0_1_ clk=clk Q=a_st1_1_ +.subckt shift D=a_2_ clk=clk Q=a_st0_2_ +.subckt shift D=a_st0_2_ clk=clk Q=a_st1_2_ +.subckt shift D=a_3_ clk=clk Q=a_st0_3_ +.subckt shift D=a_st0_3_ clk=clk Q=a_st1_3_ +.subckt shift D=a_4_ clk=clk Q=a_st0_4_ +.subckt shift D=a_st0_4_ clk=clk Q=a_st1_4_ +.subckt shift D=a_5_ clk=clk Q=a_st0_5_ +.subckt shift D=a_st0_5_ clk=clk Q=a_st1_5_ +.subckt shift D=a_6_ clk=clk Q=a_st0_6_ +.subckt shift D=a_st0_6_ clk=clk Q=a_st1_6_ + +# Pipeline b +.subckt shift D=b_0_ clk=clk Q=b_st0_0_ +.subckt shift D=b_st0_0_ clk=clk Q=b_st1_0_ +.subckt shift D=b_1_ clk=clk Q=b_st0_1_ +.subckt shift D=b_st0_1_ clk=clk Q=b_st1_1_ +.subckt shift D=b_2_ clk=clk Q=b_st0_2_ +.subckt shift D=b_st0_2_ clk=clk Q=b_st1_2_ +.subckt shift D=b_3_ clk=clk Q=b_st0_3_ +.subckt shift D=b_st0_3_ clk=clk Q=b_st1_3_ +.subckt shift D=b_4_ clk=clk Q=b_st0_4_ +.subckt shift D=b_st0_4_ clk=clk Q=b_st1_4_ +.subckt shift D=b_5_ clk=clk Q=b_st0_5_ +.subckt shift D=b_st0_5_ clk=clk Q=b_st1_5_ +.subckt shift D=b_6_ clk=clk Q=b_st0_6_ +.subckt shift D=b_st0_6_ clk=clk Q=b_st1_6_ + +# Pipeline waddr +.subckt shift D=waddr_0_ clk=clk Q=waddr_st0_0_ +.subckt shift D=waddr_st0_0_ clk=clk Q=waddr_st1_0_ +.subckt shift D=waddr_1_ clk=clk Q=waddr_st0_1_ +.subckt shift D=waddr_st0_1_ clk=clk Q=waddr_st1_1_ +.subckt shift D=waddr_2_ clk=clk Q=waddr_st0_2_ +.subckt shift D=waddr_st0_2_ clk=clk Q=waddr_st1_2_ +.subckt shift D=waddr_3_ clk=clk Q=waddr_st0_3_ +.subckt shift D=waddr_st0_3_ clk=clk Q=waddr_st1_3_ +.subckt shift D=waddr_4_ clk=clk Q=waddr_st0_4_ +.subckt shift D=waddr_st0_4_ clk=clk Q=waddr_st1_4_ +.subckt shift D=waddr_5_ clk=clk Q=waddr_st0_5_ +.subckt shift D=waddr_st0_5_ clk=clk Q=waddr_st1_5_ +# Pipeline wen +.subckt shift D=wen clk=clk Q=wen_st0 +.subckt shift D=wen_st0 clk=clk Q=wen_st1 +# End pipeline + +# Start adder +.subckt adder a=a_st1_0_ b=b_st1_0_ cin=zero00 cout=cint01 sumout=AplusB_0_ +.subckt adder a=a_st1_1_ b=b_st1_1_ cin=cint01 cout=cint02 sumout=AplusB_1_ +.subckt adder a=a_st1_2_ b=b_st1_2_ cin=cint02 cout=cint03 sumout=AplusB_2_ +.subckt adder a=a_st1_3_ b=b_st1_3_ cin=cint03 cout=cint04 sumout=AplusB_3_ +.subckt adder a=a_st1_4_ b=b_st1_4_ cin=cint04 cout=cint05 sumout=AplusB_4_ +.subckt adder a=a_st1_5_ b=b_st1_5_ cin=cint05 cout=cint06 sumout=AplusB_5_ +.subckt adder a=a_st1_6_ b=b_st1_6_ cin=cint06 cout=cint07 sumout=AplusB_6_ +.subckt adder a=zero00 b=zero00 cin=cint07 cout=unconn sumout=AplusB_7_ +# End adder + +# Start DPRAM +.subckt dual_port_ram_32x1024 clk=clk wen=wen_st1 ren=ren \ +waddr[0]=waddr_st1_0_ waddr[1]=waddr_st1_1_ waddr[2]=waddr_st1_2_ waddr[3]=waddr_st1_3_ waddr[4]=waddr_st1_4_ \ +waddr[5]=waddr_st1_5_ waddr[6]=zero00 waddr[7]=zero00 waddr[8]=zero00 \ +raddr[0]=raddr_0_ raddr[1]=raddr_1_ raddr[2]=raddr_2_ raddr[3]=raddr_3_ raddr[4]=raddr_4_ raddr[5]=raddr_5_ \ +raddr[6]=zero00 raddr[7]=zero00 raddr[8]=zero00 \ +d_in[0]=AplusB_0_ d_in[1]=AplusB_1_ d_in[2]=AplusB_2_ d_in[3]=AplusB_3_ d_in[4]=AplusB_4_ d_in[5]=AplusB_5_ \ +d_in[6]=AplusB_6_ d_in[7]=AplusB_7_ d_in[8]=zero00 d_in[9]=zero00 d_in[10]=zero00 d_in[11]=zero00 \ +d_in[12]=zero00 d_in[13]=zero00 d_in[14]=zero00 d_in[15]=zero00 d_in[16]=zero00 d_in[17]=zero00 \ +d_in[18]=zero00 d_in[19]=zero00 d_in[20]=zero00 d_in[21]=zero00 d_in[22]=zero00 d_in[23]=zero00 \ +d_in[24]=zero00 d_in[25]=zero00 d_in[26]=zero00 d_in[27]=zero00 d_in[28]=zero00 d_in[29]=zero00 \ +d_in[30]=zero00 d_in[31]=zero00 \ +d_out[0]=q_0_ d_out[1]=q_1_ d_out[2]=q_2_ d_out[3]=q_3_ d_out[4]=q_4_ d_out[5]=q_5_ \ +d_out[6]=q_6_ d_out[7]=q_7_ d_out[8]=unconn d_out[9]=unconn d_out[10]=unconn \ +d_out[11]=unconn d_out[12]=unconn d_out[13]=unconn d_out[14]=unconn d_out[15]=unconn \ +d_out[16]=unconn d_out[17]=unconn d_out[18]=unconn d_out[19]=unconn d_out[20]=unconn \ +d_out[21]=unconn d_out[22]=unconn d_out[23]=unconn d_out[24]=unconn d_out[25]=unconn \ +d_out[26]=unconn d_out[27]=unconn d_out[28]=unconn d_out[29]=unconn d_out[30]=unconn d_out[31]=unconn +# End DPRAM + +# Start global variable +.names zero00 +0 +# End global variable + + +.end + +# Start blackbox definition +.model dual_port_ram_32x1024 +.inputs clk wen ren waddr[0] waddr[1] waddr[2] waddr[3] waddr[4] waddr[5] \ + waddr[6] waddr[7] waddr[8] raddr[0] raddr[1] raddr[2] \ + raddr[3] raddr[4] raddr[5] raddr[6] raddr[7] raddr[8] \ + d_in[0] d_in[1] d_in[2] d_in[3] d_in[4] d_in[5] d_in[6] d_in[7] d_in[8] \ + d_in[9] d_in[10] d_in[11] d_in[12] d_in[13] d_in[14] d_in[15] d_in[16] \ + d_in[17] d_in[18] d_in[19] d_in[20] d_in[21] d_in[22] d_in[23] d_in[24] \ + d_in[25] d_in[26] d_in[27] d_in[28] d_in[29] d_in[30] d_in[31] +.outputs d_out[0] d_out[1] d_out[2] d_out[3] d_out[4] d_out[5] d_out[6] \ + d_out[7] d_out[8] d_out[9] d_out[10] d_out[11] d_out[12] d_out[13] \ + d_out[14] d_out[15] d_out[16] d_out[17] d_out[18] d_out[19] d_out[20] \ + d_out[21] d_out[22] d_out[23] d_out[24] d_out[25] d_out[26] d_out[27] \ + d_out[28] d_out[29] d_out[30] d_out[31] +.blackbox +.end + + +.model adder +.inputs a b cin +.outputs cout sumout +.blackbox +.end + + +.model shift +.inputs D clk +.outputs Q +.blackbox +.end +# End blackbox definition diff --git a/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.v b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.v new file mode 100644 index 000000000..549ef735a --- /dev/null +++ b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.v @@ -0,0 +1,99 @@ +// // +// ERI summit demo-benchmark // +// pipelined_8b_adder.v // +// by Aurelien // +// // +///////////////////////////////////// +//----------------------------------------------------- +// Design Name : pipelined_8bit_adder +// File Name : pipelined_8bit_adder.v +// Function : Pipelined 8-bit adders, whose sum and carry outputs +// are cached in a memory +// Coder : Aurelien Alacchi +//----------------------------------------------------- + +`timescale 1 ns/ 1 ps + +// To match the port definition in BLIF format, so that we can do verification +// Each input/output bus is expanded here. +// In future, we should be able to support buses in verification! + +module pipelined_8bit_adder( + input clk, + input ren, + input wen, + input raddr_0_, + input raddr_1_, + input raddr_2_, + input raddr_3_, + input raddr_4_, + input raddr_5_, + input waddr_0_, + input waddr_1_, + input waddr_2_, + input waddr_3_, + input waddr_4_, + input waddr_5_, + input a_0_, + input a_1_, + input a_2_, + input a_3_, + input a_4_, + input a_5_, + input a_6_, + input b_0_, + input b_1_, + input b_2_, + input b_3_, + input b_4_, + input b_5_, + input b_6_, + output q_0_, + output q_1_, + output q_2_, + output q_3_, + output q_4_, + output q_5_, + output q_6_, + output q_7_); + + wire [5:0] raddr = { raddr_5_, raddr_4_, raddr_3_, raddr_2_, raddr_1_, raddr_0_ }; + wire [5:0] waddr = { waddr_5_, waddr_4_, waddr_3_, waddr_2_, waddr_1_, waddr_0_ }; + wire [6:0] a = { a_6_, a_5_, a_4_, a_3_, a_2_, a_1_, a_0_ }; + wire [6:0] b = { b_6_, b_5_, b_4_, b_3_, b_2_, b_1_, b_0_ }; + wire [7:0] q = { q_7_, q_6_, q_5_, q_4_, q_3_, q_2_, q_1_, q_0_ }; + + reg[7:0] ram[63:0]; + reg[6:0] a_st0; + reg[6:0] a_st1; + reg[6:0] b_st0; + reg[6:0] b_st1; + reg[8:0] waddr_st0; + reg[8:0] waddr_st1; + reg wen_st0; + reg wen_st1; + reg[7:0] q_int; + + wire[7:0] AplusB; + + assign AplusB = a_st1 + b_st1; + assign q = q_int; + + always@(posedge clk) begin + waddr_st0 <= waddr; + waddr_st1 <= waddr_st0; + a_st0 <= a; + a_st1 <= a_st0; + b_st0 <= b; + b_st1 <= b_st0; + wen_st0 <= wen; + wen_st1 <= wen_st0; + if(wen_st1) begin + ram[waddr_st1] <= AplusB; + end + if(ren) begin + q_int <= ram[raddr]; + end + end + +endmodule diff --git a/openfpga_flow/tasks/heterogeneous_dpram/config/task.conf b/openfpga_flow/tasks/heterogeneous_dpram/config/task.conf new file mode 100644 index 000000000..b567b74e0 --- /dev/null +++ b/openfpga_flow/tasks/heterogeneous_dpram/config/task.conf @@ -0,0 +1,43 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = true +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=vpr_blif + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.blif + +[SYNTHESIS_PARAM] +bench0_top = pipelined_8bit_adder +bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.act +bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.v +bench0_chan_width = 100 + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +min_route_chan_width=1.3 +vpr_fpga_verilog_include_icarus_simulator= +vpr_fpga_verilog_formal_verification_top_netlist= +vpr_fpga_verilog_include_timing= +vpr_fpga_verilog_include_signal_init= +vpr_fpga_verilog_print_autocheck_top_testbench= +vpr_fpga_bitstream_generator= +#vpr_fpga_verilog_print_user_defined_template= +#vpr_fpga_verilog_print_report_timing_tcl= +#vpr_fpga_verilog_print_sdc_pnr= +#vpr_fpga_verilog_print_sdc_analysis= +vpr_fpga_verilog_explicit_mapping= +vpr_fpga_x2p_compact_routing_hierarchy= +end_flow_with_test= diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_backannotate_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_backannotate_utils.c index b8e8e8112..5b7abd0bb 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_backannotate_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_backannotate_utils.c @@ -1480,6 +1480,10 @@ void update_one_grid_pack_net_num(int x, int y) { assert ((NULL != type) && (EMPTY_TYPE != type) && (IO_TYPE != type)); + /* Bypass grids whose offset is larger than 0 ! They have been processed! */ + if (0 < grid[x][y].offset) { + return; + } for (iblk = 0; iblk < grid[x][y].usage; iblk++) { blk_id = grid[x][y].blocks[iblk]; From d391983e8c0127ed794c4dde4ab012682e73264e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 7 Nov 2019 14:57:46 -0700 Subject: [PATCH 44/68] passing regression test on dpram benchmarks --- openfpga_flow/VerilogNetlists/dpram.v | 26 +- .../k6_N10_sram_chain_HC_DPRAM_template.xml | 48 ++-- .../pipelined_8bit_adder.blif | 6 +- .../pipelined_8bit_adder.v | 30 +- ...ipelined_8bit_adder_formal_random_top_tb.v | 267 ++++++++++++++++++ 5 files changed, 326 insertions(+), 51 deletions(-) create mode 100644 openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder_formal_random_top_tb.v diff --git a/openfpga_flow/VerilogNetlists/dpram.v b/openfpga_flow/VerilogNetlists/dpram.v index 404548a95..45bdbecc0 100644 --- a/openfpga_flow/VerilogNetlists/dpram.v +++ b/openfpga_flow/VerilogNetlists/dpram.v @@ -1,20 +1,20 @@ //----------------------------------------------------- -// Design Name : dual_port_ram_32x1024 -// File Name : dpram_32x1024.v -// Function : Dual port RAM 32x1024 +// Design Name : dual_port_ram_32x512 +// File Name : dpram.v +// Function : Dual port RAM 32x512 // Coder : Aurelien Alacchi //----------------------------------------------------- -module dual_port_ram_32x1024 ( +module dual_port_ram_32x512 ( input clk, input wen, input ren, - input[0:9] waddr, - input[0:9] raddr, + input[0:8] waddr, + input[0:8] raddr, input[0:31] d_in, output[0:31] d_out ); - dual_port_sram_32x1024 memory_0 ( + dual_port_sram_32x512 memory_0 ( .wclk (clk), .wen (wen), .waddr (waddr), @@ -26,28 +26,28 @@ module dual_port_ram_32x1024 ( endmodule -module dual_port_sram_32x1024 ( +module dual_port_sram_32x512 ( input wclk, input wen, - input[0:9] waddr, + input[0:8] waddr, input[0:31] data_in, input rclk, input ren, - input[0:9] raddr, + input[0:8] raddr, output[0:31] d_out ); - reg[0:31] ram[0:1023]; + reg[0:31] ram[0:511]; reg[0:31] internal; assign d_out = internal; - always @(negedge wclk) begin + always @(posedge wclk) begin if(wen) begin ram[waddr] <= data_in; end end - always @(negedge rclk) begin + always @(posedge rclk) begin if(ren) begin internal <= ram[raddr]; end diff --git a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml index 103152e31..b053a80cd 100644 --- a/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml +++ b/openfpga_flow/arch/template/k6_N10_sram_chain_HC_DPRAM_template.xml @@ -146,7 +146,7 @@ - + @@ -421,16 +421,16 @@ - + - - - + + + - + @@ -615,29 +615,29 @@ - - - + + + - + - - - + + + - + - - - - + + + + - - + + @@ -647,8 +647,8 @@ - - + + @@ -656,8 +656,8 @@ - - + + diff --git a/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.blif b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.blif index 4ec6b2a99..a76ccdef5 100644 --- a/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.blif +++ b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.blif @@ -66,7 +66,7 @@ # End adder # Start DPRAM -.subckt dual_port_ram_32x1024 clk=clk wen=wen_st1 ren=ren \ +.subckt dual_port_ram_32x512 clk=clk wen=wen_st1 ren=ren \ waddr[0]=waddr_st1_0_ waddr[1]=waddr_st1_1_ waddr[2]=waddr_st1_2_ waddr[3]=waddr_st1_3_ waddr[4]=waddr_st1_4_ \ waddr[5]=waddr_st1_5_ waddr[6]=zero00 waddr[7]=zero00 waddr[8]=zero00 \ raddr[0]=raddr_0_ raddr[1]=raddr_1_ raddr[2]=raddr_2_ raddr[3]=raddr_3_ raddr[4]=raddr_4_ raddr[5]=raddr_5_ \ @@ -94,8 +94,8 @@ d_out[26]=unconn d_out[27]=unconn d_out[28]=unconn d_out[29]=unconn d_out[30]=un .end # Start blackbox definition -.model dual_port_ram_32x1024 -.inputs clk wen ren waddr[0] waddr[1] waddr[2] waddr[3] waddr[4] waddr[5] \ +.model dual_port_ram_32x512 +.inputs clk ren wen waddr[0] waddr[1] waddr[2] waddr[3] waddr[4] waddr[5] \ waddr[6] waddr[7] waddr[8] raddr[0] raddr[1] raddr[2] \ raddr[3] raddr[4] raddr[5] raddr[6] raddr[7] raddr[8] \ d_in[0] d_in[1] d_in[2] d_in[3] d_in[4] d_in[5] d_in[6] d_in[7] d_in[8] \ diff --git a/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.v b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.v index 549ef735a..c963eb22f 100644 --- a/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.v +++ b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder.v @@ -1,9 +1,3 @@ -// // -// ERI summit demo-benchmark // -// pipelined_8b_adder.v // -// by Aurelien // -// // -///////////////////////////////////// //----------------------------------------------------- // Design Name : pipelined_8bit_adder // File Name : pipelined_8bit_adder.v @@ -57,11 +51,25 @@ module pipelined_8bit_adder( output q_6_, output q_7_); - wire [5:0] raddr = { raddr_5_, raddr_4_, raddr_3_, raddr_2_, raddr_1_, raddr_0_ }; - wire [5:0] waddr = { waddr_5_, waddr_4_, waddr_3_, waddr_2_, waddr_1_, waddr_0_ }; - wire [6:0] a = { a_6_, a_5_, a_4_, a_3_, a_2_, a_1_, a_0_ }; - wire [6:0] b = { b_6_, b_5_, b_4_, b_3_, b_2_, b_1_, b_0_ }; - wire [7:0] q = { q_7_, q_6_, q_5_, q_4_, q_3_, q_2_, q_1_, q_0_ }; + wire [5:0] raddr; + wire [5:0] waddr; + wire [6:0] a; + wire [6:0] b; + wire [7:0] q; + + + assign raddr = { raddr_5_, raddr_4_, raddr_3_, raddr_2_, raddr_1_, raddr_0_ }; + assign waddr = { waddr_5_, waddr_4_, waddr_3_, waddr_2_, waddr_1_, waddr_0_ }; + assign a = { a_6_, a_5_, a_4_, a_3_, a_2_, a_1_, a_0_ }; + assign b = { b_6_, b_5_, b_4_, b_3_, b_2_, b_1_, b_0_ }; + assign q_7_ = q[7]; + assign q_6_ = q[6]; + assign q_5_ = q[5]; + assign q_4_ = q[4]; + assign q_3_ = q[3]; + assign q_2_ = q[2]; + assign q_1_ = q[1]; + assign q_0_ = q[0]; reg[7:0] ram[63:0]; reg[6:0] a_st0; diff --git a/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder_formal_random_top_tb.v b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder_formal_random_top_tb.v new file mode 100644 index 000000000..4276260c2 --- /dev/null +++ b/openfpga_flow/benchmarks/pipelined_8bit_adder/pipelined_8bit_adder_formal_random_top_tb.v @@ -0,0 +1,267 @@ +//----------------------------------------------------- +// Design Name : pipelined_8bit_adder_top_formal_verification_random_tb +// File Name : pipelined_8bit_adder.v +// Function : Testbench for pipelined 8-bit adders, whose sum and carry outputs +// are cached in a dual-port memory. +// This testbench will do a verification of FPGA implementation +// of the pipelined 8-bit adders against the reference +// (original) Verilog netlist +// To provide a practical testing, this testbench will : +// - Instantiate a pre-programmed FPGA and the proper +// benchmark +// - Load memories with random values +// - Randomly write and read from the memories +// - Watch for any difference between FPGA and Benchmark +// outputs, after memories are fully loaded +// +// PLEASE USE this testbench instead of the auto-generated test +// benches when performing verification! +// Coder : Aurelien Alacchi and Xifan Tang +//----------------------------------------------------- + +`timescale 1 ns/ 100 ps + +module pipelined_8bit_adder_top_formal_verification_random_tb(); + reg clk; + reg[5:0] raddr; + reg[5:0] waddr; + reg ren; + reg wen; + reg[6:0] a; + reg[6:0] b; + wire[7:0] q_gfpga; + wire[7:0] q_bench; + reg[7:0] q_flag; + + pipelined_8bit_adder_top_formal_verification DUT( + .clk_fm (clk), + .ren_fm (ren), + .wen_fm (wen), + .raddr_0__fm (raddr[0]), + .raddr_1__fm (raddr[1]), + .raddr_2__fm (raddr[2]), + .raddr_3__fm (raddr[3]), + .raddr_4__fm (raddr[4]), + .raddr_5__fm (raddr[5]), + .waddr_0__fm (waddr[0]), + .waddr_1__fm (waddr[1]), + .waddr_2__fm (waddr[2]), + .waddr_3__fm (waddr[3]), + .waddr_4__fm (waddr[4]), + .waddr_5__fm (waddr[5]), + .a_0__fm (a[0]), + .a_1__fm (a[1]), + .a_2__fm (a[2]), + .a_3__fm (a[3]), + .a_4__fm (a[4]), + .a_5__fm (a[5]), + .a_6__fm (a[6]), + .b_0__fm (b[0]), + .b_1__fm (b[1]), + .b_2__fm (b[2]), + .b_3__fm (b[3]), + .b_4__fm (b[4]), + .b_5__fm (b[5]), + .b_6__fm (b[6]), + .out_q_0__fm (q_gfpga[0]), + .out_q_1__fm (q_gfpga[1]), + .out_q_2__fm (q_gfpga[2]), + .out_q_3__fm (q_gfpga[3]), + .out_q_4__fm (q_gfpga[4]), + .out_q_5__fm (q_gfpga[5]), + .out_q_6__fm (q_gfpga[6]), + .out_q_7__fm (q_gfpga[7]) + ); + + pipelined_8bit_adder ref0( + .clk (clk), + .ren (ren), + .wen (wen), + .raddr_0_ (raddr[0]), + .raddr_1_ (raddr[1]), + .raddr_2_ (raddr[2]), + .raddr_3_ (raddr[3]), + .raddr_4_ (raddr[4]), + .raddr_5_ (raddr[5]), + .waddr_0_ (waddr[0]), + .waddr_1_ (waddr[1]), + .waddr_2_ (waddr[2]), + .waddr_3_ (waddr[3]), + .waddr_4_ (waddr[4]), + .waddr_5_ (waddr[5]), + .a_0_ (a[0]), + .a_1_ (a[1]), + .a_2_ (a[2]), + .a_3_ (a[3]), + .a_4_ (a[4]), + .a_5_ (a[5]), + .a_6_ (a[6]), + .b_0_ (b[0]), + .b_1_ (b[1]), + .b_2_ (b[2]), + .b_3_ (b[3]), + .b_4_ (b[4]), + .b_5_ (b[5]), + .b_6_ (b[6]), + .q_0_ (q_bench[0]), + .q_1_ (q_bench[1]), + .q_2_ (q_bench[2]), + .q_3_ (q_bench[3]), + .q_4_ (q_bench[4]), + .q_5_ (q_bench[5]), + .q_6_ (q_bench[6]), + .q_7_ (q_bench[7]) + ); + + integer nb_error = 0; + integer count = 0; + integer lim_max = 64 - 1; + integer write_complete = 0; + +//----- Initialization + initial begin + clk <= 1'b0; + a <= 7'h00; + b <= 7'h00; + wen <= 1'b0; + ren <= 1'b0; + waddr <= 6'h00; + raddr <= 6'h00; + while(1) begin + #2.5 + clk <= !clk; + end + end + +//----- Input Stimulis + always@(negedge clk) begin + if(write_complete == 0) begin + wen <= 1'b1; + ren <= 1'b0; + count <= count + 1; + waddr <= waddr + 1; + if(count == lim_max) begin + write_complete = 1; + end + end else begin + wen <= $random; + ren <= $random; + waddr <= $random; + raddr <= $random; + end + a <= $random; + b <= $random; + end + + + always@(negedge clk) begin + if(!(q_gfpga[0] === q_bench[0]) && !(q_bench[0] === 1'bx)) begin + q_flag[0] <= 1'b1; + end else begin + q_flag[0] <= 1'b0; + end + if(!(q_gfpga[1] === q_bench[1]) && !(q_bench[1] === 1'bx)) begin + q_flag[1] <= 1'b1; + end else begin + q_flag[1] <= 1'b0; + end + if(!(q_gfpga[2] === q_bench[2]) && !(q_bench[2] === 1'bx)) begin + q_flag[2] <= 1'b1; + end else begin + q_flag[2] <= 1'b0; + end + if(!(q_gfpga[3] === q_bench[3]) && !(q_bench[3] === 1'bx)) begin + q_flag[3] <= 1'b1; + end else begin + q_flag[3] <= 1'b0; + end + if(!(q_gfpga[4] === q_bench[4]) && !(q_bench[4] === 1'bx)) begin + q_flag[4] <= 1'b1; + end else begin + q_flag[4] <= 1'b0; + end + if(!(q_gfpga[5] === q_bench[5]) && !(q_bench[5] === 1'bx)) begin + q_flag[5] <= 1'b1; + end else begin + q_flag[5] <= 1'b0; + end + if(!(q_gfpga[6] === q_bench[6]) && !(q_bench[6] === 1'bx)) begin + q_flag[6] <= 1'b1; + end else begin + q_flag[6] <= 1'b0; + end + if(!(q_gfpga[7] === q_bench[7]) && !(q_bench[7] === 1'bx)) begin + q_flag[7] <= 1'b1; + end else begin + q_flag[7] <= 1'b0; + end + end + + + always@(posedge q_flag[0]) begin + if(q_flag[0]) begin + nb_error = nb_error + 1; + $display("Mismatch on q_gfpga[0] at time = %t", $realtime); + end + end + always@(posedge q_flag[1]) begin + if(q_flag[1]) begin + nb_error = nb_error + 1; + $display("Mismatch on q_gfpga[1] at time = %t", $realtime); + end + end + always@(posedge q_flag[2]) begin + if(q_flag[2]) begin + nb_error = nb_error + 1; + $display("Mismatch on q_gfpga[2] at time = %t", $realtime); + end + end + always@(posedge q_flag[3]) begin + if(q_flag[3]) begin + nb_error = nb_error + 1; + $display("Mismatch on q_gfpga[3] at time = %t", $realtime); + end + end + always@(posedge q_flag[4]) begin + if(q_flag[4]) begin + nb_error = nb_error + 1; + $display("Mismatch on q_gfpga[4] at time = %t", $realtime); + end + end + always@(posedge q_flag[5]) begin + if(q_flag[5]) begin + nb_error = nb_error + 1; + $display("Mismatch on q_gfpga[5] at time = %t", $realtime); + end + end + always@(posedge q_flag[6]) begin + if(q_flag[6]) begin + nb_error = nb_error + 1; + $display("Mismatch on q_gfpga[6] at time = %t", $realtime); + end + end + always@(posedge q_flag[7]) begin + if(q_flag[7]) begin + nb_error = nb_error + 1; + $display("Mismatch on q_gfpga[7] at time = %t", $realtime); + end + end + + initial begin + $dumpfile("pipelined_8bit_adder_formal.vcd"); + $dumpvars(1, pipelined_8bit_adder_top_formal_verification_random_tb); + end + + initial begin + $timeformat(-9, 2, "ns", 20); + $display("Simulation start"); + #1500 // Can be changed by the user for his need + if(nb_error == 0) begin + $display("Simulation Succeed"); + end else begin + $display("Simulation Failed with %d error(s)", nb_error); + end + $finish; + end + +endmodule From 14e7744feea229468d1f8e37d7fded6811ecf981 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 7 Nov 2019 22:20:48 -0700 Subject: [PATCH 45/68] start refactoring sdc generator, make it geneirc by placing it in parallel to Verilog generator --- vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c | 25 +++ .../vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h | 2 + .../vpr/SRC/fpga_x2p/base/fpga_x2p_utils.c | 65 ------- .../vpr/SRC/fpga_x2p/base/fpga_x2p_utils.cpp | 135 +++++++++++++++ .../vpr/SRC/fpga_x2p/base/fpga_x2p_utils.h | 18 +- .../vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.cpp | 158 ++++++++++++++++++ .../vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.h | 15 ++ vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.cpp | 34 ++++ vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.h | 13 ++ vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.cpp | 92 ++++++++++ vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.h | 43 +++++ .../vpr/SRC/fpga_x2p/sdc/sdc_writer_naming.h | 10 ++ .../vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.cpp | 52 ++++++ .../vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.h | 13 ++ .../fpga_x2p/verilog/verilog_writer_utils.cpp | 2 +- 15 files changed, 606 insertions(+), 71 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_utils.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.h create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.h create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.h create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_naming.h create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.h 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; } /******************************************************************** From 35e718b32dc639c0ac4aec2b4deebb1130f7ae9c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 8 Nov 2019 10:20:12 -0700 Subject: [PATCH 46/68] rename backend sdc generator to be backend assistant --- .../fpga_x2p/{sdc => backend_assistant}/pnr_sdc_writer.cpp | 0 .../SRC/fpga_x2p/{sdc => backend_assistant}/pnr_sdc_writer.h | 0 .../vpr/SRC/fpga_x2p/{sdc => backend_assistant}/sdc_api.cpp | 0 .../vpr/SRC/fpga_x2p/{sdc => backend_assistant}/sdc_api.h | 0 .../SRC/fpga_x2p/{sdc => backend_assistant}/sdc_option.cpp | 0 .../vpr/SRC/fpga_x2p/{sdc => backend_assistant}/sdc_option.h | 0 .../fpga_x2p/{sdc => backend_assistant}/sdc_writer_naming.h | 0 .../fpga_x2p/{sdc => backend_assistant}/sdc_writer_utils.cpp | 0 .../fpga_x2p/{sdc => backend_assistant}/sdc_writer_utils.h | 0 vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c | 4 +--- 10 files changed, 1 insertion(+), 3 deletions(-) rename vpr7_x2p/vpr/SRC/fpga_x2p/{sdc => backend_assistant}/pnr_sdc_writer.cpp (100%) rename vpr7_x2p/vpr/SRC/fpga_x2p/{sdc => backend_assistant}/pnr_sdc_writer.h (100%) rename vpr7_x2p/vpr/SRC/fpga_x2p/{sdc => backend_assistant}/sdc_api.cpp (100%) rename vpr7_x2p/vpr/SRC/fpga_x2p/{sdc => backend_assistant}/sdc_api.h (100%) rename vpr7_x2p/vpr/SRC/fpga_x2p/{sdc => backend_assistant}/sdc_option.cpp (100%) rename vpr7_x2p/vpr/SRC/fpga_x2p/{sdc => backend_assistant}/sdc_option.h (100%) rename vpr7_x2p/vpr/SRC/fpga_x2p/{sdc => backend_assistant}/sdc_writer_naming.h (100%) rename vpr7_x2p/vpr/SRC/fpga_x2p/{sdc => backend_assistant}/sdc_writer_utils.cpp (100%) rename vpr7_x2p/vpr/SRC/fpga_x2p/{sdc => backend_assistant}/sdc_writer_utils.h (100%) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp similarity index 100% rename from vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.cpp rename to vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h similarity index 100% rename from vpr7_x2p/vpr/SRC/fpga_x2p/sdc/pnr_sdc_writer.h rename to vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp similarity index 100% rename from vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.cpp rename to vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h similarity index 100% rename from vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_api.h rename to vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.cpp similarity index 100% rename from vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.cpp rename to vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.cpp diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.h similarity index 100% rename from vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_option.h rename to vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h similarity index 100% rename from vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_naming.h rename to vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp similarity index 100% rename from vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.cpp rename to vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h similarity index 100% rename from vpr7_x2p/vpr/SRC/fpga_x2p/sdc/sdc_writer_utils.h rename to vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h 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 966a8cb5d..403ba8bee 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 @@ -147,9 +147,7 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, 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 { + if (false == src_dir.empty()) { src_dir = format_dir_path(src_dir); } SdcOption sdc_options(format_dir_path(src_dir + std::string(FPGA_X2P_DEFAULT_SDC_DIR))); From 33b3705ced99c9230200fd0c7ae4e241a2621fcb Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 8 Nov 2019 11:15:35 -0700 Subject: [PATCH 47/68] refactoring disable outputs sdc generation --- .../backend_assistant/pnr_sdc_writer.cpp | 64 ++++++++++++++++++- .../fpga_x2p/backend_assistant/sdc_option.cpp | 55 ++++++++++++---- .../fpga_x2p/backend_assistant/sdc_option.h | 13 ++-- .../backend_assistant/sdc_writer_naming.h | 4 +- vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c | 2 +- 5 files changed, 117 insertions(+), 21 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp index d2f41e023..746f7a4a3 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp @@ -43,7 +43,7 @@ void print_pnr_sdc_global_ports(const std::string& sdc_dir, const std::vector& global_ports) { /* Create the file name for Verilog netlist */ - std::string sdc_fname(sdc_dir + std::string(SDC_CLOCK_FILE_NAME)); + std::string sdc_fname(sdc_dir + std::string(SDC_GLOBAL_PORTS_FILE_NAME)); vpr_printf(TIO_MESSAGE_INFO, "Generating SDC for constraining clocks for P&R flow: %s ...", @@ -138,6 +138,47 @@ void print_pnr_sdc_global_ports(const std::string& sdc_dir, run_time_sec); } +/******************************************************************** + * Break combintational loops in FPGA fabric, which mainly come from: + * 1. Configurable memory cells. + * To handle this, we disable the outputs of memory cells + * 2. Loops of multiplexers. + * To handle this, we disable the outputs of routing multiplexers + *******************************************************************/ +static +void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_dir) { + + /* Create the file name for Verilog netlist */ + std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_CONFIG_MEM_OUTPUTS_FILE_NAME)); + + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for disable configurable memory outputs 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("disable configurable memory outputs for PnR")); + + /* 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 @@ -155,4 +196,25 @@ void print_pnr_sdc(const SdcOption& sdc_options, if (true == sdc_options.constrain_global_port()) { print_pnr_sdc_global_ports(sdc_options.sdc_dir(), critical_path_delay, circuit_lib, global_ports); } + + /* Part 2. Output Design Constraints to disable outputs of memory cells */ + if (true == sdc_options.constrain_configurable_memory_outputs()) { + print_pnr_sdc_constrain_configurable_memory_outputs(sdc_options.sdc_dir()); + } + + /* 2. Break loops from Multiplexer Output */ + /* + if (TRUE == sdc_opts.break_loops_mux) { + verilog_generate_sdc_break_loop_mux(fp, num_switch, switches, spice, routing_arch); + } + */ + + /* TODO: 3. Break loops from any SB output */ + /* + if (TRUE == sdc_opts.compact_routing_hierarchy) { + verilog_generate_sdc_break_loop_sb(fp, LL_device_rr_gsb); + } else { + verilog_generate_sdc_break_loop_sb(fp, LL_nx, LL_ny); + } + */ } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.cpp index ca9753b5d..088266337 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.cpp @@ -8,14 +8,15 @@ ********************************************************************/ 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; + constrain_global_port_ = false; + constrain_grid_ = false; + constrain_sb_ = false; + constrain_cb_ = false; + constrain_configurable_memory_outputs_ = false; + constrain_routing_multiplexer_outputs_ = false; + constrain_switch_block_outputs_ = false; } - /******************************************************************** * Public accessors ********************************************************************/ @@ -24,11 +25,17 @@ std::string SdcOption::sdc_dir() const { } bool SdcOption::generate_sdc() const { - return generate_sdc_pnr_ && generate_sdc_analysis_; + return generate_sdc_pnr() && generate_sdc_analysis_; } bool SdcOption::generate_sdc_pnr() const { - return generate_sdc_pnr_; + return constrain_global_port_ + || constrain_grid_ + || constrain_sb_ + || constrain_cb_ + || constrain_configurable_memory_outputs_ + || constrain_routing_multiplexer_outputs_ + || constrain_switch_block_outputs_; } bool SdcOption::generate_sdc_analysis() const { @@ -51,8 +58,16 @@ bool SdcOption::constrain_cb() const { return constrain_cb_; } -bool SdcOption::break_loop() const { - return break_loop_; +bool SdcOption::constrain_configurable_memory_outputs() const { + return constrain_configurable_memory_outputs_; +} + +bool SdcOption::constrain_routing_multiplexer_outputs() const { + return constrain_routing_multiplexer_outputs_; +} + +bool SdcOption::constrain_switch_block_outputs() const { + return constrain_switch_block_outputs_; } /******************************************************************** @@ -63,7 +78,13 @@ void SdcOption::set_sdc_dir(const std::string& sdc_dir) { } void SdcOption::set_generate_sdc_pnr(const bool& generate_sdc_pnr) { - generate_sdc_pnr_ = generate_sdc_pnr; + constrain_global_port_ = generate_sdc_pnr; + constrain_grid_ = generate_sdc_pnr; + constrain_sb_ = generate_sdc_pnr; + constrain_cb_ = generate_sdc_pnr; + constrain_configurable_memory_outputs_ = generate_sdc_pnr; + constrain_routing_multiplexer_outputs_ = generate_sdc_pnr; + constrain_switch_block_outputs_ = generate_sdc_pnr; } void SdcOption::set_generate_sdc_analysis(const bool& generate_sdc_analysis) { @@ -86,7 +107,15 @@ 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; +void SdcOption::set_constrain_configurable_memory_outputs(const bool& constrain_config_mem_outputs) { + constrain_configurable_memory_outputs_ = constrain_config_mem_outputs; +} + +void SdcOption::set_constrain_routing_multiplexer_outputs(const bool& constrain_routing_mux_outputs) { + constrain_routing_multiplexer_outputs_ = constrain_routing_mux_outputs; +} + +void SdcOption::set_constrain_switch_block_outputs(const bool& constrain_sb_outputs) { + constrain_switch_block_outputs_ = constrain_sb_outputs; } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.h index 244ffc796..ee6192830 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_option.h @@ -19,7 +19,9 @@ class SdcOption { bool constrain_grid() const; bool constrain_sb() const; bool constrain_cb() const; - bool break_loop() const; + bool constrain_configurable_memory_outputs() const; + bool constrain_routing_multiplexer_outputs() const; + bool constrain_switch_block_outputs() const; public: /* Public mutators */ void set_sdc_dir(const std::string& sdc_dir); void set_generate_sdc_pnr(const bool& generate_sdc_pnr); @@ -28,15 +30,18 @@ class SdcOption { 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); + void set_constrain_configurable_memory_outputs(const bool& constrain_config_mem_outputs); + void set_constrain_routing_multiplexer_outputs(const bool& constrain_routing_mux_outputs); + void set_constrain_switch_block_outputs(const bool& constrain_sb_outputs); 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 constrain_configurable_memory_outputs_; + bool constrain_routing_multiplexer_outputs_; + bool constrain_switch_block_outputs_; bool generate_sdc_analysis_; }; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h index 0fdb2f2b7..7b9df4804 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h @@ -1,9 +1,9 @@ #ifndef SDC_WRITER_NAMING_H #define SDC_WRITER_NAMING_H -constexpr char* SDC_CLOCK_FILE_NAME = "clb_clock.sdc"; +constexpr char* SDC_GLOBAL_PORTS_FILE_NAME = "global_ports.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_DISABLE_CONFIG_MEM_OUTPUTS_FILE_NAME = "disable_configurable_memory_outputs.sdc"; constexpr char* SDC_CB_FILE_NAME = "cb.sdc"; constexpr char* SDC_SB_FILE_NAME = "sb.sdc"; 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 403ba8bee..dabd837a8 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 @@ -151,7 +151,7 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, 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_pnr(FALSE == 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()) { From ea7c981c8529607ddcf47ffde67fb3a593eb9142 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 8 Nov 2019 15:01:30 -0700 Subject: [PATCH 48/68] critical bugs fixed for routing module naming; and speed up local wire detection in Verilog writer --- .../bitstream/build_routing_bitstream.cpp | 6 +-- .../module_builder/build_routing_modules.cpp | 2 +- .../verilog/verilog_module_writer.cpp | 46 +++++++++++-------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/build_routing_bitstream.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/build_routing_bitstream.cpp index 5d2c558ad..48c4a0504 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/build_routing_bitstream.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/build_routing_bitstream.cpp @@ -248,7 +248,7 @@ void build_connection_block_interc_bitstream(BitstreamManager& bitstream_manager /* No bitstream generation required by a special direct connection*/ } else if (1 < src_rr_node->fan_in) { /* Create the block denoting the memory instances that drives this node in Switch Block */ - std::string mem_block_name = generate_cb_memory_instance_name(CONNECTION_BLOCK_MEM_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, ipin_index), src_rr_node->ptc_num, std::string("")); + std::string mem_block_name = generate_cb_memory_instance_name(CONNECTION_BLOCK_MEM_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, ipin_index), ipin_index, std::string("")); ConfigBlockId mux_mem_block = bitstream_manager.add_block(mem_block_name); bitstream_manager.add_child_block(cb_configurable_block, mux_mem_block); /* This is a routing multiplexer! Generate bitstream */ @@ -380,13 +380,13 @@ void build_routing_bitstream(BitstreamManager& bitstream_manager, * To organize the bitstream in blocks, we create a block for each connection block * and give names which are same as they are in top-level module managers */ - vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for X-directionConnection blocks ...\n"); + vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for X-direction Connection blocks ...\n"); build_connection_block_bitstreams(bitstream_manager, top_configurable_block, module_manager, circuit_lib, mux_lib, rr_switches, L_rr_node, L_device_rr_gsb, CHANX); - vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for Y-directionConnection blocks ...\n"); + vpr_printf(TIO_MESSAGE_INFO,"Generating bitstream for Y-direction Connection blocks ...\n"); build_connection_block_bitstreams(bitstream_manager, top_configurable_block, module_manager, circuit_lib, mux_lib, rr_switches, L_rr_node, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp index 35fd4a296..c460f45b4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp @@ -780,7 +780,7 @@ void build_connection_block_mux_module(ModuleManager& module_manager, /* Give an instance name: this name should be consistent with the block name given in bitstream manager, * If you want to bind the bitstream generation to modules */ - std::string mem_instance_name = generate_cb_memory_instance_name(CONNECTION_BLOCK_MEM_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, ipin_index), cur_rr_node->ptc_num, std::string("")); + std::string mem_instance_name = generate_cb_memory_instance_name(CONNECTION_BLOCK_MEM_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, ipin_index), ipin_index, std::string("")); module_manager.set_child_instance_name(cb_module, mem_module, mem_instance_id, mem_instance_name); /* Add nets to connect regular and mode-select SRAM ports to the SRAM port of memory module */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_module_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_module_writer.cpp index 3a4bebcf8..0b89a87e2 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_module_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_module_writer.cpp @@ -95,9 +95,9 @@ BasicPort generate_verilog_port_for_module_net(const ModuleManager& module_manag * to write up local wire declaration in Verilog format *******************************************************************/ static -std::vector find_verilog_module_local_wires(const ModuleManager& module_manager, - const ModuleId& module_id) { - std::vector local_wires; +std::map> find_verilog_module_local_wires(const ModuleManager& module_manager, + const ModuleId& module_id) { + std::map> local_wires; /* Local wires come from the child modules */ for (ModuleNetId module_net : module_manager.module_nets(module_id)) { @@ -119,20 +119,28 @@ std::vector find_verilog_module_local_wires(const ModuleManager& modu } /* Find the name for this local wire */ BasicPort local_wire_candidate = generate_verilog_port_for_module_net(module_manager, module_id, module_net); - /* Try to find a port in the list that can absorb the current local wire */ + /* Cache the net name, try to find it in the cache. + * If you can find one, it means this port may be mergeable, try to do merging. If merge fail, add to the local wire list + * If you cannot find one, it means that this port is not mergeable, add to the local wire list immediately. + */ + std::map>::iterator it = local_wires.find(local_wire_candidate.get_name()); bool merged = false; - for (BasicPort& local_wire : local_wires) { - /* check if the candidate can be combined to an existing local wire */ - if (true == two_verilog_ports_mergeable(local_wire, local_wire_candidate)) { - /* Merge the ports */ - local_wire = merge_two_verilog_ports(local_wire, local_wire_candidate); - merged = true; - break; - } + if (it != local_wires.end()) { + /* Try to merge to one the port in the list that can absorb the current local wire */ + for (BasicPort& local_wire : local_wires[local_wire_candidate.get_name()]) { + /* check if the candidate can be combined to an existing local wire */ + if (true == two_verilog_ports_mergeable(local_wire, local_wire_candidate)) { + /* Merge the ports */ + local_wire = merge_two_verilog_ports(local_wire, local_wire_candidate); + merged = true; + break; + } + } } - /* If not merged, push the port to the list */ + + /* If not merged/not found in the cache, push the port to the list */ if (false == merged) { - local_wires.push_back(local_wire_candidate); + local_wires[local_wire_candidate.get_name()].push_back(local_wire_candidate); } } @@ -161,7 +169,7 @@ std::vector find_verilog_module_local_wires(const ModuleManager& modu instance_port.set_width(*std::min_element(undriven_pins.begin(), undriven_pins.end()), *std::max_element(undriven_pins.begin(), undriven_pins.end())); - local_wires.push_back(instance_port); + local_wires[instance_port.get_name()].push_back(instance_port); } } } @@ -436,9 +444,11 @@ void write_verilog_module_to_file(std::fstream& fp, fp << std::endl; /* Print internal wires */ - std::vector local_wires = find_verilog_module_local_wires(module_manager, module_id); - for (BasicPort local_wire : local_wires) { - fp << generate_verilog_port(VERILOG_PORT_WIRE, local_wire) << ";" << std::endl; + std::map> local_wires = find_verilog_module_local_wires(module_manager, module_id); + for (std::pair> port_group : local_wires) { + for (const BasicPort& local_wire : port_group.second) { + fp << generate_verilog_port(VERILOG_PORT_WIRE, local_wire) << ";" << std::endl; + } } /* Print an empty line as splitter */ From e273c00c9d76512265b3ca5316b4e0934fb4362c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 8 Nov 2019 17:38:07 -0700 Subject: [PATCH 49/68] add refactored disable timing for memory cells --- .../backend_assistant/pnr_sdc_writer.cpp | 73 ++++++++++++++++++- .../backend_assistant/pnr_sdc_writer.h | 2 + .../fpga_x2p/backend_assistant/sdc_api.cpp | 4 +- .../SRC/fpga_x2p/backend_assistant/sdc_api.h | 2 + vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c | 4 +- 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp index 746f7a4a3..042efac5e 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp @@ -17,6 +17,7 @@ #include "util.h" +#include "fpga_x2p_naming.h" #include "fpga_x2p_utils.h" #include "sdc_writer_naming.h" @@ -139,14 +140,70 @@ void print_pnr_sdc_global_ports(const std::string& sdc_dir, } /******************************************************************** - * Break combintational loops in FPGA fabric, which mainly come from: + * Print SDC commands to disable outputs of all the configurable memory modules + * in a given module + * This function will be executed in a recursive way, + * using a Depth-First Search (DFS) strategy + * It will iterate over all the configurable children under each module + * and print a SDC command to disable its outputs + *******************************************************************/ +static +void rec_print_pnr_sdc_disable_configurable_memory_module_output(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& parent_module_path) { + + /* For each configurable child, we will go one level down in priority */ + for (size_t child_index = 0; child_index < module_manager.configurable_children(parent_module).size(); ++child_index) { + std::string child_module_path = parent_module_path; + ModuleId child_module_id = module_manager.configurable_children(parent_module)[child_index]; + size_t child_instance_id = module_manager.configurable_child_instances(parent_module)[child_index]; + if (true == module_manager.instance_name(parent_module, child_module_id, child_instance_id).empty()) { + /* Give a default name __ */ + child_module_path += module_manager.module_name(child_module_id); + child_module_path += "_"; + child_module_path += std::to_string(child_instance_id); + child_module_path += "_"; + } else { + child_module_path += module_manager.instance_name(parent_module, child_module_id, child_instance_id); + } + child_module_path = format_dir_path(child_module_path); + + rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, module_manager, + child_module_id, + child_module_path); + } + + /* If there is no configurable children any more, this is a leaf module, print a SDC command for disable timing */ + if (0 < module_manager.configurable_children(parent_module).size()) { + return; + } + + /* Validate file stream */ + check_file_handler(fp); + + /* Disable timing for each output port of this module */ + for (const BasicPort& output_port : module_manager.module_ports_by_type(parent_module, ModuleManager::MODULE_OUTPUT_PORT)) { + for (const size_t& pin : output_port.pins()) { + BasicPort output_pin(output_port.get_name(), pin, pin); + fp << "set_disable_timing "; + fp << parent_module_path << generate_sdc_port(output_pin); + fp << std::endl; + } + } +} + +/******************************************************************** + * Break combinational loops in FPGA fabric, which mainly come from: * 1. Configurable memory cells. * To handle this, we disable the outputs of memory cells * 2. Loops of multiplexers. * To handle this, we disable the outputs of routing multiplexers *******************************************************************/ static -void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_dir) { +void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_dir, + const ModuleManager& module_manager, + const ModuleId& top_module) { /* Create the file name for Verilog netlist */ std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_CONFIG_MEM_OUTPUTS_FILE_NAME)); @@ -165,7 +222,11 @@ void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_ check_file_handler(fp); /* Generate the descriptions*/ - print_sdc_file_header(fp, std::string("disable configurable memory outputs for PnR")); + print_sdc_file_header(fp, std::string("Disable configurable memory outputs for PnR")); + + /* Go recursively in the module manager, starting from the top-level module: instance id of the top-level module is 0 by default */ + rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, module_manager, top_module, + format_dir_path(module_manager.module_name(top_module))); /* Close file handler */ fp.close(); @@ -190,6 +251,7 @@ void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_ void print_pnr_sdc(const SdcOption& sdc_options, const float& critical_path_delay, const CircuitLibrary& circuit_lib, + const ModuleManager& module_manager, const std::vector& global_ports) { /* Part 1. Constrain global ports */ @@ -199,7 +261,10 @@ void print_pnr_sdc(const SdcOption& sdc_options, /* Part 2. Output Design Constraints to disable outputs of memory cells */ if (true == sdc_options.constrain_configurable_memory_outputs()) { - print_pnr_sdc_constrain_configurable_memory_outputs(sdc_options.sdc_dir()); + std::string top_module_name = generate_fpga_top_module_name(); + ModuleId top_module = module_manager.find_module(top_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(top_module)); + print_pnr_sdc_constrain_configurable_memory_outputs(sdc_options.sdc_dir(), module_manager, top_module); } /* 2. Break loops from Multiplexer Output */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h index 8b0b4496a..492a18873 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h @@ -5,11 +5,13 @@ #include "vtr_geometry.h" #include "vpr_types.h" #include "rr_blocks.h" +#include "module_manager.h" #include "sdc_option.h" void print_pnr_sdc(const SdcOption& sdc_options, const float& critical_path_delay, const CircuitLibrary& circuit_lib, + const ModuleManager& module_manager, const std::vector& global_ports); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp index 8162f9ff1..f6d46561b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp @@ -12,6 +12,7 @@ void fpga_sdc_generator(const SdcOption& sdc_options, const float& critical_path_delay, const CircuitLibrary& circuit_lib, + const ModuleManager& module_manager, const std::vector& global_ports) { vpr_printf(TIO_MESSAGE_INFO, "SDC generator starts..."); @@ -20,7 +21,7 @@ void fpga_sdc_generator(const SdcOption& sdc_options, 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); + print_pnr_sdc(sdc_options, critical_path_delay, circuit_lib, module_manager, global_ports); } /* End time count */ @@ -30,5 +31,4 @@ void fpga_sdc_generator(const SdcOption& sdc_options, vpr_printf(TIO_MESSAGE_INFO, "SDC generation took %g seconds\n", run_time_sec); - } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h index fe630963e..fbd9960d8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h @@ -4,10 +4,12 @@ #include #include "sdc_option.h" #include "circuit_library.h" +#include "module_manager.h" void fpga_sdc_generator(const SdcOption& sdc_options, const float& critical_path_delay, const CircuitLibrary& circuit_lib, + const ModuleManager& module_manager, const std::vector& global_ports); #endif 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 dabd837a8..ccecccabd 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 @@ -151,7 +151,7 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, 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(FALSE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_sdc_pnr); + 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()) { @@ -159,7 +159,7 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, /* 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); + Arch.spice->circuit_lib, module_manager, global_ports); } /* Xifan Tang: Bitstream Generator */ From be574b0d45ee93c609db9cc9289315638cc26aea Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 8 Nov 2019 19:05:05 -0700 Subject: [PATCH 50/68] refactored disable routing mux outputs --- .../backend_assistant/pnr_sdc_writer.cpp | 91 ++++++++++++++++--- .../backend_assistant/pnr_sdc_writer.h | 3 + .../fpga_x2p/backend_assistant/sdc_api.cpp | 3 +- .../SRC/fpga_x2p/backend_assistant/sdc_api.h | 2 + .../backend_assistant/sdc_writer_naming.h | 1 + vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c | 1 + 6 files changed, 88 insertions(+), 13 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp index 042efac5e..1fb4ebeaa 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp @@ -16,6 +16,7 @@ #include "device_port.h" #include "util.h" +#include "mux_utils.h" #include "fpga_x2p_naming.h" #include "fpga_x2p_utils.h" @@ -194,11 +195,9 @@ void rec_print_pnr_sdc_disable_configurable_memory_module_output(std::fstream& f } /******************************************************************** - * Break combinational loops in FPGA fabric, which mainly come from: - * 1. Configurable memory cells. - * To handle this, we disable the outputs of memory cells - * 2. Loops of multiplexers. - * To handle this, we disable the outputs of routing multiplexers + * Break combinational loops in FPGA fabric, which mainly come from + * configurable memory cells. + * To handle this, we disable the outputs of memory cells *******************************************************************/ static void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_dir, @@ -240,6 +239,72 @@ void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_ run_time_sec); } +/******************************************************************** + * Break combinational loops in FPGA fabric, which mainly come from + * loops of multiplexers. + * To handle this, we disable the timing at outputs of routing multiplexers + *******************************************************************/ +static +void print_sdc_disable_routing_multiplexer_outputs(const std::string& sdc_dir, + const MuxLibrary& mux_lib, + const CircuitLibrary& circuit_lib, + const ModuleManager& module_manager) { + /* Create the file name for Verilog netlist */ + std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_MUX_OUTPUTS_FILE_NAME)); + + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for disable routing multiplexer outputs 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("Disable routing multiplexer outputs for PnR")); + + /* Iterate over the MUX modules */ + for (const MuxId& mux_id : mux_lib.muxes()) { + const CircuitModelId& mux_model = mux_lib.mux_circuit_model(mux_id); + + /* Skip LUTs, we only care about multiplexers here */ + if (SPICE_MODEL_MUX != circuit_lib.model_type(mux_model)) { + continue; + } + + const MuxGraph& mux_graph = mux_lib.mux_graph(mux_id); + std::string mux_module_name = generate_mux_subckt_name(circuit_lib, mux_model, + find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()), + std::string("")); + /* Find the module name in module manager */ + ModuleId mux_module = module_manager.find_module(mux_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(mux_module)); + + /* Disable the timing for the output ports */ + for (const BasicPort& output_port : module_manager.module_ports_by_type(mux_module, ModuleManager::MODULE_OUTPUT_PORT)) { + fp << "set_disable_timing [get_pins -filter \"name =~ " << output_port.get_name() << "*\" "; + fp << "-of [get_cells -hier -filter \"ref_lib_cell_name == " << mux_module_name << "\"]]" << 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 @@ -250,6 +315,7 @@ void print_pnr_sdc_constrain_configurable_memory_outputs(const std::string& sdc_ *******************************************************************/ void print_pnr_sdc(const SdcOption& sdc_options, const float& critical_path_delay, + const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, const ModuleManager& module_manager, const std::vector& global_ports) { @@ -259,20 +325,21 @@ void print_pnr_sdc(const SdcOption& sdc_options, print_pnr_sdc_global_ports(sdc_options.sdc_dir(), critical_path_delay, circuit_lib, global_ports); } + std::string top_module_name = generate_fpga_top_module_name(); + ModuleId top_module = module_manager.find_module(top_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(top_module)); + /* Part 2. Output Design Constraints to disable outputs of memory cells */ if (true == sdc_options.constrain_configurable_memory_outputs()) { - std::string top_module_name = generate_fpga_top_module_name(); - ModuleId top_module = module_manager.find_module(top_module_name); - VTR_ASSERT(true == module_manager.valid_module_id(top_module)); print_pnr_sdc_constrain_configurable_memory_outputs(sdc_options.sdc_dir(), module_manager, top_module); } /* 2. Break loops from Multiplexer Output */ - /* - if (TRUE == sdc_opts.break_loops_mux) { - verilog_generate_sdc_break_loop_mux(fp, num_switch, switches, spice, routing_arch); + if (true == sdc_options.constrain_routing_multiplexer_outputs()) { + print_sdc_disable_routing_multiplexer_outputs(sdc_options.sdc_dir(), + mux_lib, circuit_lib, + module_manager); } - */ /* TODO: 3. Break loops from any SB output */ /* diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h index 492a18873..6923320a6 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h @@ -6,10 +6,13 @@ #include "vpr_types.h" #include "rr_blocks.h" #include "module_manager.h" +#include "mux_library.h" +#include "circuit_library.h" #include "sdc_option.h" void print_pnr_sdc(const SdcOption& sdc_options, const float& critical_path_delay, + const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, const ModuleManager& module_manager, const std::vector& global_ports); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp index f6d46561b..99a981df8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp @@ -11,6 +11,7 @@ *******************************************************************/ void fpga_sdc_generator(const SdcOption& sdc_options, const float& critical_path_delay, + const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, const ModuleManager& module_manager, const std::vector& global_ports) { @@ -21,7 +22,7 @@ void fpga_sdc_generator(const SdcOption& sdc_options, clock_t t_start = clock(); if (true == sdc_options.generate_sdc_pnr()) { - print_pnr_sdc(sdc_options, critical_path_delay, circuit_lib, module_manager, global_ports); + print_pnr_sdc(sdc_options, critical_path_delay, mux_lib, circuit_lib, module_manager, global_ports); } /* End time count */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h index fbd9960d8..e0f64fafd 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h @@ -4,10 +4,12 @@ #include #include "sdc_option.h" #include "circuit_library.h" +#include "mux_library.h" #include "module_manager.h" void fpga_sdc_generator(const SdcOption& sdc_options, const float& critical_path_delay, + const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, const ModuleManager& module_manager, const std::vector& global_ports); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h index 7b9df4804..7371835a8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h @@ -4,6 +4,7 @@ constexpr char* SDC_GLOBAL_PORTS_FILE_NAME = "global_ports.sdc"; constexpr char* SDC_BENCHMARK_ANALYSIS_FILE_NAME= "fpga_top_analysis.sdc"; constexpr char* SDC_DISABLE_CONFIG_MEM_OUTPUTS_FILE_NAME = "disable_configurable_memory_outputs.sdc"; +constexpr char* SDC_DISABLE_MUX_OUTPUTS_FILE_NAME = "disable_routing_multiplexer_outputs.sdc"; constexpr char* SDC_CB_FILE_NAME = "cb.sdc"; constexpr char* SDC_SB_FILE_NAME = "sb.sdc"; 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 ccecccabd..8c1f6b5e2 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 @@ -159,6 +159,7 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, /* 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, + mux_lib, Arch.spice->circuit_lib, module_manager, global_ports); } From 4b5ecc516bb9127e89ce6650fb47f43c5cd0e204 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 9 Nov 2019 10:52:15 -0700 Subject: [PATCH 51/68] refactored SDC SB constrain generation --- .../backend_assistant/pnr_sdc_writer.cpp | 389 +++++++++++++++++- .../backend_assistant/pnr_sdc_writer.h | 8 +- .../fpga_x2p/backend_assistant/sdc_api.cpp | 14 +- .../SRC/fpga_x2p/backend_assistant/sdc_api.h | 8 +- .../backend_assistant/sdc_writer_naming.h | 4 +- .../backend_assistant/sdc_writer_utils.cpp | 29 ++ .../backend_assistant/sdc_writer_utils.h | 8 + vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c | 6 +- .../build_routing_module_utils.cpp | 219 ++++++++++ .../build_routing_module_utils.h | 49 +++ .../module_builder/build_routing_modules.cpp | 213 +--------- 11 files changed, 715 insertions(+), 232 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp index 1fb4ebeaa..a693d0c2c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp @@ -21,6 +21,8 @@ #include "fpga_x2p_naming.h" #include "fpga_x2p_utils.h" +#include "build_routing_module_utils.h" + #include "sdc_writer_naming.h" #include "sdc_writer_utils.h" #include "pnr_sdc_writer.h" @@ -305,6 +307,327 @@ void print_sdc_disable_routing_multiplexer_outputs(const std::string& sdc_dir, run_time_sec); } +/******************************************************************** + * Break combinational loops in FPGA fabric, which mainly come from + * loops of multiplexers. + * To handle this, we disable the timing at outputs of Switch blocks + * This function is designed for flatten routing hierarchy + *******************************************************************/ +static +void print_pnr_sdc_flatten_routing_disable_switch_block_outputs(const std::string& sdc_dir, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb) { + /* Create the file name for Verilog netlist */ + std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_SB_OUTPUTS_FILE_NAME)); + + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for disable Switch Block outputs 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("Disable Switch Block outputs for PnR")); + + /* Get the range of SB array */ + DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range(); + /* Go for each SB */ + for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { + const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); + vtr::Point gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); + std::string sb_instance_name = generate_switch_block_module_name(gsb_coordinate); + + ModuleId sb_module = module_manager.find_module(sb_instance_name); + VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); + + /* Disable the outputs of the module */ + for (const BasicPort& output_port : module_manager.module_ports_by_type(sb_module, ModuleManager::MODULE_OUTPUT_PORT)) { + fp << "set_disable_timing " << sb_instance_name << "/" << output_port.get_name() << 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); +} + +/******************************************************************** + * Break combinational loops in FPGA fabric, which mainly come from + * loops of multiplexers. + * To handle this, we disable the timing at outputs of Switch blocks + * This function is designed for compact routing hierarchy + *******************************************************************/ +static +void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::string& sdc_dir, + const ModuleManager& module_manager, + const ModuleId& top_module, + const DeviceRRGSB& L_device_rr_gsb) { + /* Create the file name for Verilog netlist */ + std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_SB_OUTPUTS_FILE_NAME)); + + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for disable Switch Block outputs 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("Disable Switch Block outputs for PnR")); + + /* Build unique switch block modules */ + for (size_t isb = 0; isb < L_device_rr_gsb.get_num_sb_unique_module(); ++isb) { + const RRGSB& rr_gsb = L_device_rr_gsb.get_sb_unique_module(isb); + vtr::Point gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); + std::string sb_module_name = generate_switch_block_module_name(gsb_coordinate); + + ModuleId sb_module = module_manager.find_module(sb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); + + /* Find all the instances in the top-level module */ + for (const size_t& instance_id : module_manager.child_module_instances(top_module, sb_module)) { + std::string sb_instance_name = module_manager.instance_name(top_module, sb_module, instance_id); + /* Disable the outputs of the module */ + for (const BasicPort& output_port : module_manager.module_ports_by_type(sb_module, ModuleManager::MODULE_OUTPUT_PORT)) { + fp << "set_disable_timing " << sb_instance_name << "/" << output_port.get_name() << 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); +} + +/******************************************************************** + * Find the timing constraints between the inputs and outputs of a routing + * multiplexer in a Switch Block + *******************************************************************/ +static +float find_pnr_sdc_switch_tmax(const t_switch_inf& switch_inf) { + return switch_inf.R * switch_inf.Cout + switch_inf.Tdel; +} + +/******************************************************************** + * Set timing constraints between the inputs and outputs of a routing + * multiplexer in a Switch Block + *******************************************************************/ +static +void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& sb_module, + const RRGSB& rr_gsb, + const std::vector>& grids, + const std::vector& switches, + const e_side& output_node_side, + t_rr_node* output_rr_node) { + /* Validate file stream */ + check_file_handler(fp); + + VTR_ASSERT( ( CHANX == output_rr_node->type ) + || ( CHANY == output_rr_node->type )); + + /* Find the module port corresponding to the output rr_node */ + ModulePortId module_output_port = find_switch_block_module_chan_port(module_manager, + sb_module, + rr_gsb, + output_node_side, + output_rr_node, + OUT_PORT); + + /* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */ + std::vector input_rr_nodes; + for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { + input_rr_nodes.push_back(output_rr_node->drive_rr_nodes[iedge]); + } + + std::vector module_input_ports = find_switch_block_module_input_ports(module_manager, + sb_module, + rr_gsb, + grids, + input_rr_nodes); + + /* Find timing constraints for each path (edge) */ + std::map switch_delays; + for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { + /* Get the switch delay */ + int switch_id = output_rr_node->drive_switches[iedge]; + switch_delays[module_input_ports[iedge]] = find_pnr_sdc_switch_tmax(switches[switch_id]); + } + + /* Find the starting points */ + for (const ModulePortId& module_input_port : module_input_ports) { + /* Constrain a path */ + print_pnr_sdc_constrain_module_port2port_timing(fp, + module_manager, sb_module, + module_input_port, module_output_port, + switch_delays[module_input_port]); + } +} + +/******************************************************************** + * Set timing constraints between the inputs and outputs of SBs, + * which are connected by routing multiplexers with the given delays + * specified in architectural XML file + * + * To enable block by block timing constraining, we generate the SDC + * file for each unique SB module + *******************************************************************/ +static +void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const RRGSB& rr_gsb) { + + /* Create the file name for Verilog netlist */ + vtr::Point gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); + std::string sdc_fname(sdc_dir + generate_switch_block_module_name(gsb_coordinate) + std::string(SDC_FILE_NAME_POSTFIX)); + + /* Create the file stream */ + std::fstream fp; + fp.open(sdc_fname, std::fstream::out | std::fstream::trunc); + + /* Validate file stream */ + check_file_handler(fp); + + std::string sb_module_name = generate_switch_block_module_name(gsb_coordinate); + ModuleId sb_module = module_manager.find_module(sb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); + + /* Generate the descriptions*/ + print_sdc_file_header(fp, std::string("Constrain timing of Switch Block " + sb_module_name + " outputs for PnR")); + + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) { + t_rr_node* chan_rr_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack); + /* We only care the output port and it should indicate a SB mux */ + if (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { + continue; + } + /* Constrain thru wires */ + if (false != rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack)) { + continue; + } + /* This is a MUX, constrain all the paths from an input to an output */ + print_pnr_sdc_constrain_sb_mux_timing(fp, + module_manager, sb_module, + rr_gsb, + grids, switches, + side_manager.get_side(), + chan_rr_node); + } + } + + /* Close file handler */ + fp.close(); +} + +/******************************************************************** + * Print SDC timing constraints for Switch blocks + * This function is designed for flatten routing hierarchy + *******************************************************************/ +static +void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb) { + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for constrain Switch Block timing for P&R flow..."); + + /* Start time count */ + clock_t t_start = clock(); + + /* Get the range of SB array */ + DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range(); + /* Go for each SB */ + for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { + const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); + print_pnr_sdc_constrain_sb_timing(sdc_dir, + module_manager, + grids, switches, + rr_gsb); + } + } + + /* 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); +} + +/******************************************************************** + * Break combinational loops in FPGA fabric, which mainly come from + * loops of multiplexers. + * To handle this, we disable the timing at outputs of Switch blocks + * This function is designed for compact routing hierarchy + *******************************************************************/ +static +void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb) { + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for constrain Switch Block timing for P&R flow..."); + + /* Start time count */ + clock_t t_start = clock(); + + for (size_t isb = 0; isb < L_device_rr_gsb.get_num_sb_unique_module(); ++isb) { + const RRGSB& rr_gsb = L_device_rr_gsb.get_sb_unique_module(isb); + print_pnr_sdc_constrain_sb_timing(sdc_dir, + module_manager, + grids, switches, + rr_gsb); + } + + /* 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 @@ -315,12 +638,16 @@ void print_sdc_disable_routing_multiplexer_outputs(const std::string& sdc_dir, *******************************************************************/ void print_pnr_sdc(const SdcOption& sdc_options, const float& critical_path_delay, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb, + const ModuleManager& module_manager, const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, - const ModuleManager& module_manager, - const std::vector& global_ports) { + const std::vector& global_ports, + const bool& compact_routing_hierarchy) { - /* Part 1. Constrain global ports */ + /* 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); } @@ -329,24 +656,66 @@ void print_pnr_sdc(const SdcOption& sdc_options, ModuleId top_module = module_manager.find_module(top_module_name); VTR_ASSERT(true == module_manager.valid_module_id(top_module)); - /* Part 2. Output Design Constraints to disable outputs of memory cells */ + /* Output Design Constraints to disable outputs of memory cells */ if (true == sdc_options.constrain_configurable_memory_outputs()) { print_pnr_sdc_constrain_configurable_memory_outputs(sdc_options.sdc_dir(), module_manager, top_module); } - /* 2. Break loops from Multiplexer Output */ + /* Break loops from Multiplexer Output */ if (true == sdc_options.constrain_routing_multiplexer_outputs()) { print_sdc_disable_routing_multiplexer_outputs(sdc_options.sdc_dir(), mux_lib, circuit_lib, module_manager); } - /* TODO: 3. Break loops from any SB output */ + /* Break loops from any SB output */ + if (true == sdc_options.constrain_switch_block_outputs()) { + if (true == compact_routing_hierarchy) { + print_pnr_sdc_compact_routing_disable_switch_block_outputs(sdc_options.sdc_dir(), + module_manager, top_module, + L_device_rr_gsb); + } else { + VTR_ASSERT_SAFE (false == compact_routing_hierarchy); + print_pnr_sdc_flatten_routing_disable_switch_block_outputs(sdc_options.sdc_dir(), + module_manager, + L_device_rr_gsb); + } + } + + /* Output routing constraints for Switch Blocks */ + if (true == sdc_options.constrain_sb()) { + if (true == compact_routing_hierarchy) { + print_pnr_sdc_compact_routing_constrain_sb_timing(sdc_options.sdc_dir(), + module_manager, + grids, switches, + L_device_rr_gsb); + } else { + VTR_ASSERT_SAFE (false == compact_routing_hierarchy); + print_pnr_sdc_flatten_routing_constrain_sb_timing(sdc_options.sdc_dir(), + module_manager, + grids, switches, + L_device_rr_gsb); + } + } + + /* TODO: Output routing constraints for Connection Blocks */ /* - if (TRUE == sdc_opts.compact_routing_hierarchy) { - verilog_generate_sdc_break_loop_sb(fp, LL_device_rr_gsb); - } else { - verilog_generate_sdc_break_loop_sb(fp, LL_nx, LL_ny); + if (true == sdc_options.constrain_cb()) { + if (true == compact_routing_hierarchy) { + verilog_generate_sdc_constrain_cbs(sdc_opts, LL_nx, LL_ny, LL_device_rr_gsb); + } else { + VTR_ASSERT_SAFE (false == compact_routing_hierarchy); + verilog_generate_sdc_constrain_cbs(sdc_opts, + LL_nx, LL_ny); + } + } + */ + + /* TODO: Output routing constraints for Programmable blocks */ + /* + if (true == sdc_options.constrain_grid()) { + verilog_generate_sdc_constrain_pb_types(cur_sram_orgz_info, + sdc_dir); } */ } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h index 6923320a6..6b618b2df 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.h @@ -12,9 +12,13 @@ void print_pnr_sdc(const SdcOption& sdc_options, const float& critical_path_delay, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb, + const ModuleManager& module_manager, const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, - const ModuleManager& module_manager, - const std::vector& global_ports); + const std::vector& global_ports, + const bool& compact_routing_hierarchy); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp index 99a981df8..690e456c5 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp @@ -11,10 +11,14 @@ *******************************************************************/ void fpga_sdc_generator(const SdcOption& sdc_options, const float& critical_path_delay, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb, + const ModuleManager& module_manager, const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, - const ModuleManager& module_manager, - const std::vector& global_ports) { + const std::vector& global_ports, + const bool& compact_routing_hierarchy) { vpr_printf(TIO_MESSAGE_INFO, "SDC generator starts..."); @@ -22,7 +26,11 @@ void fpga_sdc_generator(const SdcOption& sdc_options, clock_t t_start = clock(); if (true == sdc_options.generate_sdc_pnr()) { - print_pnr_sdc(sdc_options, critical_path_delay, mux_lib, circuit_lib, module_manager, global_ports); + print_pnr_sdc(sdc_options, critical_path_delay, + grids, switches, L_device_rr_gsb, + module_manager, mux_lib, + circuit_lib, global_ports, + compact_routing_hierarchy); } /* End time count */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h index e0f64fafd..d53dc201a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h @@ -9,9 +9,13 @@ void fpga_sdc_generator(const SdcOption& sdc_options, const float& critical_path_delay, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb, + const ModuleManager& module_manager, const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, - const ModuleManager& module_manager, - const std::vector& global_ports); + const std::vector& global_ports, + const bool& compact_routing_hierarchy); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h index 7371835a8..e479f95d3 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h @@ -1,11 +1,13 @@ #ifndef SDC_WRITER_NAMING_H #define SDC_WRITER_NAMING_H +constexpr char* SDC_FILE_NAME_POSTFIX = ".sdc"; + constexpr char* SDC_GLOBAL_PORTS_FILE_NAME = "global_ports.sdc"; constexpr char* SDC_BENCHMARK_ANALYSIS_FILE_NAME= "fpga_top_analysis.sdc"; constexpr char* SDC_DISABLE_CONFIG_MEM_OUTPUTS_FILE_NAME = "disable_configurable_memory_outputs.sdc"; constexpr char* SDC_DISABLE_MUX_OUTPUTS_FILE_NAME = "disable_routing_multiplexer_outputs.sdc"; +constexpr char* SDC_DISABLE_SB_OUTPUTS_FILE_NAME = "disable_sb_outputs.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/backend_assistant/sdc_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp index 12ef60b6b..6a74c290d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp @@ -3,6 +3,7 @@ *******************************************************************/ #include #include +#include #include "fpga_x2p_utils.h" @@ -50,3 +51,31 @@ std::string generate_sdc_port(const BasicPort& port) { return sdc_line; } + +/******************************************************************** + * Constrain a path between two ports of a module with a given timing value + *******************************************************************/ +void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& module_id, + const ModulePortId& module_input_port_id, + const ModulePortId& module_output_port_id, + const float& tmax) { + /* Validate file stream */ + check_file_handler(fp); + + fp << "set_max_delay"; + + fp << " -from "; + fp << module_manager.module_name(module_id) << "/"; + fp << generate_sdc_port(module_manager.module_port(module_id, module_input_port_id)); + + fp << " -to "; + + fp << module_manager.module_name(module_id) << "/"; + fp << generate_sdc_port(module_manager.module_port(module_id, module_output_port_id)); + + fp << " " << std::setprecision(10) << tmax; + + fp << std::endl; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h index b3d916f57..d4c2ae860 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h @@ -4,10 +4,18 @@ #include #include #include "device_port.h" +#include "module_manager.h" void print_sdc_file_header(std::fstream& fp, const std::string& usage); std::string generate_sdc_port(const BasicPort& port); +void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& module_id, + const ModulePortId& module_input_port_id, + const ModulePortId& module_output_port_id, + const float& tmax); + #endif 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 8c1f6b5e2..a254d4824 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 @@ -159,8 +159,10 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, /* 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, - mux_lib, - Arch.spice->circuit_lib, module_manager, global_ports); + grids, rr_switches, device_rr_gsb, + module_manager, mux_lib, + Arch.spice->circuit_lib, global_ports, + TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy); } /* Xifan Tang: Bitstream Generator */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.cpp new file mode 100644 index 000000000..a81eb567f --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.cpp @@ -0,0 +1,219 @@ +/******************************************************************** + * This file includes most utilized functions that are used to build modules + * for global routing architecture of a FPGA fabric + * Covering: + * 1. Connection blocks + * 2. Switch blocks + *******************************************************************/ +#include "vtr_assert.h" +#include "vtr_geometry.h" +#include "device_coordinator.h" + +#include "fpga_x2p_naming.h" + +#include "build_routing_module_utils.h" + +/********************************************************************* + * Generate a port for a routing track of a swtich block + ********************************************************************/ +ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_manager, + const ModuleId& sb_module, + const RRGSB& rr_gsb, + const e_side& chan_side, + t_rr_node* cur_rr_node, + const PORTS& cur_rr_node_direction) { + /* Get the index in sb_info of cur_rr_node */ + int index = rr_gsb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction); + /* Make sure this node is included in this sb_info */ + VTR_ASSERT((-1 != index)&&(NUM_SIDES != chan_side)); + + DeviceCoordinator chan_rr_node_coordinator = rr_gsb.get_side_block_coordinator(chan_side); + + vtr::Point chan_port_coord(chan_rr_node_coordinator.get_x(), chan_rr_node_coordinator.get_y()); + std::string chan_port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(chan_side, index)->type, + chan_port_coord, index, + rr_gsb.get_chan_node_direction(chan_side, index)); + + /* Must find a valid port id in the Switch Block module */ + ModulePortId chan_port_id = module_manager.find_module_port(sb_module, chan_port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, chan_port_id)); + return chan_port_id; +} + +/********************************************************************* + * Generate an input port for routing multiplexer inside the switch block + * In addition to give the Routing Resource node of the input + * Users should provide the side of input, which is different case by case: + * 1. When the input is a pin of a CLB/Logic Block, the input_side should + * be the side of the node on its grid! + * For example, the input pin is on the top side of a switch block + * but on the right side of a switch block + * +--------+ + * | | + * | Grid |---+ + * | | | + * +--------+ v input_pin + * +----------------+ + * | Switch Block | + * +----------------+ + * 2. When the input is a routing track, the input_side should be + * the side of the node locating on the switch block + ********************************************************************/ +ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager, + const ModuleId& sb_module, + const RRGSB& rr_gsb, + const std::vector>& grids, + const e_side& input_side, + t_rr_node* input_rr_node) { + /* Deposit an invalid value */ + ModulePortId input_port_id = ModulePortId::INVALID(); + /* Generate the input port object */ + switch (input_rr_node->type) { + /* case SOURCE: */ + case OPIN: { + /* Find the coordinator (grid_x and grid_y) for the input port */ + vtr::Point input_port_coord(input_rr_node->xlow, input_rr_node->ylow); + std::string input_port_name = generate_grid_side_port_name(grids, + input_port_coord, + input_side, + input_rr_node->ptc_num); + /* Must find a valid port id in the Switch Block module */ + input_port_id = module_manager.find_module_port(sb_module, input_port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, input_port_id)); + break; + } + case CHANX: + case CHANY: { + input_port_id = find_switch_block_module_chan_port(module_manager, sb_module, + rr_gsb, input_side, input_rr_node, IN_PORT); + break; + } + default: /* SOURCE, IPIN, SINK are invalid*/ + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n", + __FILE__, __LINE__); + exit(1); + } + + return input_port_id; +} + +/********************************************************************* + * Generate a list of input ports for routing multiplexer inside the switch block + ********************************************************************/ +std::vector find_switch_block_module_input_ports(const ModuleManager& module_manager, + const ModuleId& sb_module, + const RRGSB& rr_gsb, + const std::vector>& grids, + const std::vector& input_rr_nodes) { + std::vector input_ports; + + for (auto input_rr_node : input_rr_nodes) { + enum e_side input_pin_side = NUM_SIDES; + switch (input_rr_node->type) { + case OPIN: + input_pin_side = rr_gsb.get_opin_node_grid_side(input_rr_node); + break; + case CHANX: + case CHANY: { + /* The input could be at any side of the switch block, find it */ + int index = -1; + rr_gsb.get_node_side_and_index(input_rr_node, IN_PORT, &input_pin_side, &index); + VTR_ASSERT(NUM_SIDES != input_pin_side); + break; + } + default: /* SOURCE, IPIN, SINK are invalid*/ + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n", + __FILE__, __LINE__); + exit(1); + } + input_ports.push_back(find_switch_block_module_input_port(module_manager, sb_module, rr_gsb, grids, input_pin_side, input_rr_node)); + } + + return input_ports; +} + +/********************************************************************* + * Generate an input port for routing multiplexer inside the connection block + * which is the middle output of a routing track + ********************************************************************/ +ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_manager, + const ModuleId& cb_module, + const RRGSB& rr_gsb, + const t_rr_type& cb_type, + t_rr_node* chan_rr_node) { + ModulePortId input_port_id; + /* Generate the input port object */ + switch (chan_rr_node->type) { + case CHANX: + case CHANY: { + /* Create port description for the routing track middle output */ + vtr::Point port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); + int chan_node_track_id = rr_gsb.get_cb_chan_node_index(cb_type, chan_rr_node); + /* Create a port description for the middle output */ + std::string input_port_name = generate_routing_track_port_name(cb_type, + port_coord, chan_node_track_id, + IN_PORT); + /* Must find a valid port id in the Switch Block module */ + input_port_id = module_manager.find_module_port(cb_module, input_port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, input_port_id)); + break; + } + default: /* OPIN, SOURCE, IPIN, SINK are invalid*/ + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n", + __FILE__, __LINE__); + exit(1); + } + + return input_port_id; +} + +/********************************************************************* + * Generate a port for a routing track of a swtich block + ********************************************************************/ +ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager, + const ModuleId& cb_module, + const RRGSB& rr_gsb, + const std::vector>& grids, + t_rr_node* src_rr_node) { + + /* Ensure the src_rr_node is an input pin of a CLB */ + VTR_ASSERT(IPIN == src_rr_node->type); + /* Create port description for input pin of a CLB */ + vtr::Point port_coord(src_rr_node->xlow, src_rr_node->ylow); + /* Search all the sides of a SB, see this drive_rr_node is an INPUT of this SB */ + enum e_side cb_ipin_side = NUM_SIDES; + int cb_ipin_index = -1; + rr_gsb.get_node_side_and_index(src_rr_node, OUT_PORT, &cb_ipin_side, &cb_ipin_index); + /* We need to be sure that drive_rr_node is part of the CB */ + VTR_ASSERT((-1 != cb_ipin_index)&&(NUM_SIDES != cb_ipin_side)); + std::string port_name = generate_grid_side_port_name(grids, + port_coord, + rr_gsb.get_ipin_node_grid_side(cb_ipin_side, cb_ipin_index), + rr_gsb.get_ipin_node(cb_ipin_side, cb_ipin_index)->ptc_num); + + /* Must find a valid port id in the Switch Block module */ + ModulePortId ipin_port_id = module_manager.find_module_port(cb_module, port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, ipin_port_id)); + return ipin_port_id; +} + +/********************************************************************* + * Generate a list of routing track middle output ports + * for routing multiplexer inside the connection block + ********************************************************************/ +std::vector find_connection_block_module_input_ports(const ModuleManager& module_manager, + const ModuleId& cb_module, + const RRGSB& rr_gsb, + const t_rr_type& cb_type, + const std::vector& input_rr_nodes) { + std::vector input_ports; + + for (auto input_rr_node : input_rr_nodes) { + input_ports.push_back(find_connection_block_module_chan_port(module_manager, cb_module, rr_gsb, cb_type, input_rr_node)); + } + + return input_ports; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.h new file mode 100644 index 000000000..aa423b12e --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.h @@ -0,0 +1,49 @@ +#ifndef BUILD_ROUTING_MODULE_UTILS_H +#define BUILD_ROUTING_MODULE_UTILS_H + +#include +#include "rr_blocks.h" +#include "module_manager.h" +#include "sides.h" +#include "vpr_types.h" + +ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_manager, + const ModuleId& sb_module, + const RRGSB& rr_gsb, + const e_side& chan_side, + t_rr_node* cur_rr_node, + const PORTS& cur_rr_node_direction); + +ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager, + const ModuleId& sb_module, + const RRGSB& rr_gsb, + const std::vector>& grids, + const e_side& input_side, + t_rr_node* input_rr_node); + +std::vector find_switch_block_module_input_ports(const ModuleManager& module_manager, + const ModuleId& sb_module, + const RRGSB& rr_gsb, + const std::vector>& grids, + const std::vector& input_rr_nodes); + +ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_manager, + const ModuleId& cb_module, + const RRGSB& rr_gsb, + const t_rr_type& cb_type, + t_rr_node* chan_rr_node); + +ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager, + const ModuleId& cb_module, + const RRGSB& rr_gsb, + const std::vector>& grids, + t_rr_node* src_rr_node); + + +std::vector find_connection_block_module_input_ports(const ModuleManager& module_manager, + const ModuleId& cb_module, + const RRGSB& rr_gsb, + const t_rr_type& cb_type, + const std::vector& input_rr_nodes); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp index c460f45b4..d2b5b4464 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp @@ -21,135 +21,11 @@ #include "fpga_x2p_utils.h" #include "module_manager_utils.h" #include "build_module_graph_utils.h" +#include "build_routing_module_utils.h" #include "build_routing_modules.h" #include "verilog_global.h" -/********************************************************************* - * Generate a port for a routing track of a swtich block - ********************************************************************/ -static -ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_manager, - const ModuleId& sb_module, - const RRGSB& rr_gsb, - const e_side& chan_side, - t_rr_node* cur_rr_node, - const PORTS& cur_rr_node_direction) { - /* Get the index in sb_info of cur_rr_node */ - int index = rr_gsb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction); - /* Make sure this node is included in this sb_info */ - VTR_ASSERT((-1 != index)&&(NUM_SIDES != chan_side)); - - DeviceCoordinator chan_rr_node_coordinator = rr_gsb.get_side_block_coordinator(chan_side); - - vtr::Point chan_port_coord(chan_rr_node_coordinator.get_x(), chan_rr_node_coordinator.get_y()); - std::string chan_port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(chan_side, index)->type, - chan_port_coord, index, - rr_gsb.get_chan_node_direction(chan_side, index)); - - /* Must find a valid port id in the Switch Block module */ - ModulePortId chan_port_id = module_manager.find_module_port(sb_module, chan_port_name); - VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, chan_port_id)); - return chan_port_id; -} - -/********************************************************************* - * Generate an input port for routing multiplexer inside the switch block - * In addition to give the Routing Resource node of the input - * Users should provide the side of input, which is different case by case: - * 1. When the input is a pin of a CLB/Logic Block, the input_side should - * be the side of the node on its grid! - * For example, the input pin is on the top side of a switch block - * but on the right side of a switch block - * +--------+ - * | | - * | Grid |---+ - * | | | - * +--------+ v input_pin - * +----------------+ - * | Switch Block | - * +----------------+ - * 2. When the input is a routing track, the input_side should be - * the side of the node locating on the switch block - ********************************************************************/ -static -ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager, - const ModuleId& sb_module, - const RRGSB& rr_gsb, - const std::vector>& grids, - const e_side& input_side, - t_rr_node* input_rr_node) { - /* Deposit an invalid value */ - ModulePortId input_port_id = ModulePortId::INVALID(); - /* Generate the input port object */ - switch (input_rr_node->type) { - /* case SOURCE: */ - case OPIN: { - /* Find the coordinator (grid_x and grid_y) for the input port */ - vtr::Point input_port_coord(input_rr_node->xlow, input_rr_node->ylow); - std::string input_port_name = generate_grid_side_port_name(grids, - input_port_coord, - input_side, - input_rr_node->ptc_num); - /* Must find a valid port id in the Switch Block module */ - input_port_id = module_manager.find_module_port(sb_module, input_port_name); - VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, input_port_id)); - break; - } - case CHANX: - case CHANY: { - input_port_id = find_switch_block_module_chan_port(module_manager, sb_module, - rr_gsb, input_side, input_rr_node, IN_PORT); - break; - } - default: /* SOURCE, IPIN, SINK are invalid*/ - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n", - __FILE__, __LINE__); - exit(1); - } - - return input_port_id; -} - -/********************************************************************* - * Generate a list of input ports for routing multiplexer inside the switch block - ********************************************************************/ -static -std::vector find_switch_block_module_input_ports(const ModuleManager& module_manager, - const ModuleId& sb_module, - const RRGSB& rr_gsb, - const std::vector>& grids, - const std::vector& input_rr_nodes) { - std::vector input_ports; - - for (auto input_rr_node : input_rr_nodes) { - enum e_side input_pin_side = NUM_SIDES; - switch (input_rr_node->type) { - case OPIN: - input_pin_side = rr_gsb.get_opin_node_grid_side(input_rr_node); - break; - case CHANX: - case CHANY: { - /* The input could be at any side of the switch block, find it */ - int index = -1; - rr_gsb.get_node_side_and_index(input_rr_node, IN_PORT, &input_pin_side, &index); - VTR_ASSERT(NUM_SIDES != input_pin_side); - break; - } - default: /* SOURCE, IPIN, SINK are invalid*/ - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n", - __FILE__, __LINE__); - exit(1); - } - input_ports.push_back(find_switch_block_module_input_port(module_manager, sb_module, rr_gsb, grids, input_pin_side, input_rr_node)); - } - - return input_ports; -} - - /********************************************************************* * Generate a short interconneciton in switch box * There are two cases should be noticed. @@ -550,93 +426,6 @@ void build_switch_block_module(ModuleManager& module_manager, } } -/********************************************************************* - * Generate an input port for routing multiplexer inside the connection block - * which is the middle output of a routing track - ********************************************************************/ -static -ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_manager, - const ModuleId& cb_module, - const RRGSB& rr_gsb, - const t_rr_type& cb_type, - t_rr_node* chan_rr_node) { - ModulePortId input_port_id; - /* Generate the input port object */ - switch (chan_rr_node->type) { - case CHANX: - case CHANY: { - /* Create port description for the routing track middle output */ - vtr::Point port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); - int chan_node_track_id = rr_gsb.get_cb_chan_node_index(cb_type, chan_rr_node); - /* Create a port description for the middle output */ - std::string input_port_name = generate_routing_track_port_name(cb_type, - port_coord, chan_node_track_id, - IN_PORT); - /* Must find a valid port id in the Switch Block module */ - input_port_id = module_manager.find_module_port(cb_module, input_port_name); - VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, input_port_id)); - break; - } - default: /* OPIN, SOURCE, IPIN, SINK are invalid*/ - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n", - __FILE__, __LINE__); - exit(1); - } - - return input_port_id; -} - -/********************************************************************* - * Generate a port for a routing track of a swtich block - ********************************************************************/ -static -ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager, - const ModuleId& cb_module, - const RRGSB& rr_gsb, - const std::vector>& grids, - t_rr_node* src_rr_node) { - - /* Ensure the src_rr_node is an input pin of a CLB */ - VTR_ASSERT(IPIN == src_rr_node->type); - /* Create port description for input pin of a CLB */ - vtr::Point port_coord(src_rr_node->xlow, src_rr_node->ylow); - /* Search all the sides of a SB, see this drive_rr_node is an INPUT of this SB */ - enum e_side cb_ipin_side = NUM_SIDES; - int cb_ipin_index = -1; - rr_gsb.get_node_side_and_index(src_rr_node, OUT_PORT, &cb_ipin_side, &cb_ipin_index); - /* We need to be sure that drive_rr_node is part of the CB */ - VTR_ASSERT((-1 != cb_ipin_index)&&(NUM_SIDES != cb_ipin_side)); - std::string port_name = generate_grid_side_port_name(grids, - port_coord, - rr_gsb.get_ipin_node_grid_side(cb_ipin_side, cb_ipin_index), - rr_gsb.get_ipin_node(cb_ipin_side, cb_ipin_index)->ptc_num); - - /* Must find a valid port id in the Switch Block module */ - ModulePortId ipin_port_id = module_manager.find_module_port(cb_module, port_name); - VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, ipin_port_id)); - return ipin_port_id; -} - -/********************************************************************* - * Generate a list of routing track middle output ports - * for routing multiplexer inside the connection block - ********************************************************************/ -static -std::vector find_connection_block_module_input_ports(const ModuleManager& module_manager, - const ModuleId& cb_module, - const RRGSB& rr_gsb, - const t_rr_type& cb_type, - const std::vector& input_rr_nodes) { - std::vector input_ports; - - for (auto input_rr_node : input_rr_nodes) { - input_ports.push_back(find_connection_block_module_chan_port(module_manager, cb_module, rr_gsb, cb_type, input_rr_node)); - } - - return input_ports; -} - /********************************************************************* * Print a short interconneciton in connection ********************************************************************/ From a7f2a61d0d964ceea35872a2de97f24843a4477f Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 9 Nov 2019 11:42:38 -0700 Subject: [PATCH 52/68] refactored CB SDC generation --- .../backend_assistant/pnr_sdc_writer.cpp | 244 +++++++++++++++++- .../build_routing_module_utils.h | 1 - 2 files changed, 234 insertions(+), 11 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp index a693d0c2c..70b8f00ab 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp @@ -527,7 +527,7 @@ void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir, VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); /* Generate the descriptions*/ - print_sdc_file_header(fp, std::string("Constrain timing of Switch Block " + sb_module_name + " outputs for PnR")); + print_sdc_file_header(fp, std::string("Constrain timing of Switch Block " + sb_module_name + " for PnR")); for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { Side side_manager(side); @@ -594,9 +594,7 @@ void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_di } /******************************************************************** - * Break combinational loops in FPGA fabric, which mainly come from - * loops of multiplexers. - * To handle this, we disable the timing at outputs of Switch blocks + * Print SDC timing constraints for Switch blocks * This function is designed for compact routing hierarchy *******************************************************************/ static @@ -628,6 +626,227 @@ void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_di run_time_sec); } +/******************************************************************** + * Set timing constraints between the inputs and outputs of a routing + * multiplexer in a Connection Block + *******************************************************************/ +static +void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& cb_module, + const RRGSB& rr_gsb, + const t_rr_type& cb_type, + const std::vector>& grids, + const std::vector& switches, + t_rr_node* output_rr_node) { + /* Validate file stream */ + check_file_handler(fp); + + VTR_ASSERT(IPIN == output_rr_node->type); + + /* Find the module port corresponding to the output rr_node */ + ModulePortId module_output_port = find_connection_block_module_ipin_port(module_manager, + cb_module, + rr_gsb, + grids, output_rr_node); + + /* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */ + std::vector input_rr_nodes; + for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { + input_rr_nodes.push_back(output_rr_node->drive_rr_nodes[iedge]); + } + + std::vector module_input_ports = find_connection_block_module_input_ports(module_manager, + cb_module, + rr_gsb, + cb_type, + input_rr_nodes); + + /* Find timing constraints for each path (edge) */ + std::map switch_delays; + for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { + /* Get the switch delay */ + int switch_id = output_rr_node->drive_switches[iedge]; + switch_delays[module_input_ports[iedge]] = find_pnr_sdc_switch_tmax(switches[switch_id]); + } + + /* Find the starting points */ + for (const ModulePortId& module_input_port : module_input_ports) { + /* Constrain a path */ + print_pnr_sdc_constrain_module_port2port_timing(fp, + module_manager, cb_module, + module_input_port, module_output_port, + switch_delays[module_input_port]); + } +} + + +/******************************************************************** + * Print SDC timing constraints for a Connection block + * This function is designed for compact routing hierarchy + *******************************************************************/ +static +void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const RRGSB& rr_gsb, + const t_rr_type& cb_type, + const std::vector>& grids, + const std::vector& switches) { + /* Create the netlist */ + vtr::Point gsb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); + + /* Find the module name and create a SDC file for it */ + std::string sdc_fname(sdc_dir + generate_connection_block_module_name(cb_type, gsb_coordinate) + std::string(SDC_FILE_NAME_POSTFIX)); + + /* Create the file stream */ + std::fstream fp; + fp.open(sdc_fname, std::fstream::out | std::fstream::trunc); + + /* Validate file stream */ + check_file_handler(fp); + + std::string cb_module_name = generate_connection_block_module_name(cb_type, gsb_coordinate); + ModuleId cb_module = module_manager.find_module(cb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(cb_module)); + + /* Generate the descriptions*/ + print_sdc_file_header(fp, std::string("Constrain timing of Connection Block " + cb_module_name + " for PnR")); + + std::vector cb_sides = rr_gsb.get_cb_ipin_sides(cb_type); + + for (size_t side = 0; side < cb_sides.size(); ++side) { + enum e_side cb_ipin_side = cb_sides[side]; + Side side_manager(cb_ipin_side); + for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) { + t_rr_node* ipin_rr_node = rr_gsb.get_ipin_node(cb_ipin_side, inode); + print_pnr_sdc_constrain_cb_mux_timing(fp, + module_manager, cb_module, + rr_gsb, cb_type, + grids, switches, + ipin_rr_node); + } + } + + /* Close file handler */ + fp.close(); +} + +/******************************************************************** + * Iterate over all the connection blocks in a device + * and print SDC file for each of them + *******************************************************************/ +static +void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const std::vector>& grids, + const std::vector& switches, + const t_rr_type& cb_type) { + /* Build unique X-direction connection block modules */ + DeviceCoordinator cb_range = L_device_rr_gsb.get_gsb_range(); + + for (size_t ix = 0; ix < cb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < cb_range.get_y(); ++iy) { + /* Check if the connection block exists in the device! + * Some of them do NOT exist due to heterogeneous blocks (height > 1) + * We will skip those modules + */ + const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); + if (false == rr_gsb.is_cb_exist(cb_type)) { + continue; + } + print_pnr_sdc_constrain_cb_timing(sdc_dir, + module_manager, + rr_gsb, + cb_type, + grids, switches); + + } + } +} + +/******************************************************************** + * Iterate over all the connection blocks in a device + * and print SDC file for each of them + *******************************************************************/ +static +void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const std::vector>& grids, + const std::vector& switches) { + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for constrain Connection Block timing for P&R flow..."); + + /* Start time count */ + clock_t t_start = clock(); + + print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager, + L_device_rr_gsb, + grids, + switches, + CHANX); + + print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager, + L_device_rr_gsb, + grids, + switches, + CHANY); + + /* 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); +} + +/******************************************************************** + * Print SDC timing constraints for Connection blocks + * This function is designed for compact routing hierarchy + *******************************************************************/ +static +void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb) { + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for constrain Connection Block timing for P&R flow..."); + + /* Start time count */ + clock_t t_start = clock(); + + /* Print SDC for unique X-direction connection block modules */ + for (size_t icb = 0; icb < L_device_rr_gsb.get_num_cb_unique_module(CHANX); ++icb) { + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(CHANX, icb); + print_pnr_sdc_constrain_cb_timing(sdc_dir, + module_manager, + unique_mirror, + CHANX, + grids, switches); + } + + /* Print SDC for unique Y-direction connection block modules */ + for (size_t icb = 0; icb < L_device_rr_gsb.get_num_cb_unique_module(CHANY); ++icb) { + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(CHANY, icb); + print_pnr_sdc_constrain_cb_timing(sdc_dir, + module_manager, + unique_mirror, + CHANY, + grids, switches); + } + + /* 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 @@ -698,18 +917,23 @@ void print_pnr_sdc(const SdcOption& sdc_options, } } - /* TODO: Output routing constraints for Connection Blocks */ - /* + /* Output routing constraints for Connection Blocks */ if (true == sdc_options.constrain_cb()) { if (true == compact_routing_hierarchy) { - verilog_generate_sdc_constrain_cbs(sdc_opts, LL_nx, LL_ny, LL_device_rr_gsb); + print_pnr_sdc_compact_routing_constrain_cb_timing(sdc_options.sdc_dir(), + module_manager, + grids, + switches, + L_device_rr_gsb); } else { VTR_ASSERT_SAFE (false == compact_routing_hierarchy); - verilog_generate_sdc_constrain_cbs(sdc_opts, - LL_nx, LL_ny); + print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_options.sdc_dir(), + module_manager, + L_device_rr_gsb, + grids, + switches); } } - */ /* TODO: Output routing constraints for Programmable blocks */ /* diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.h index aa423b12e..db684ea0a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_module_utils.h @@ -39,7 +39,6 @@ ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_ const std::vector>& grids, t_rr_node* src_rr_node); - std::vector find_connection_block_module_input_ports(const ModuleManager& module_manager, const ModuleId& cb_module, const RRGSB& rr_gsb, From d226d18d40332d01492861bc25aff091b841256f Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 9 Nov 2019 11:54:05 -0700 Subject: [PATCH 53/68] move SDC generator for routing modules to an independent source file --- .../pnr_sdc_routing_writer.cpp | 440 ++++++++++++++++++ .../pnr_sdc_routing_writer.h | 34 ++ .../backend_assistant/pnr_sdc_writer.cpp | 420 +---------------- 3 files changed, 475 insertions(+), 419 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp new file mode 100644 index 000000000..9fbe46b4c --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp @@ -0,0 +1,440 @@ +/******************************************************************** + * 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 routing modules + * in FPGA fabric, such as 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 "vtr_assert.h" +#include "device_port.h" + +#include "util.h" +#include "mux_utils.h" + +#include "fpga_x2p_naming.h" +#include "fpga_x2p_utils.h" + +#include "build_routing_module_utils.h" + +#include "sdc_writer_naming.h" +#include "sdc_writer_utils.h" +#include "pnr_sdc_routing_writer.h" + +/******************************************************************** + * Find the timing constraints between the inputs and outputs of a routing + * multiplexer in a Switch Block + *******************************************************************/ +static +float find_pnr_sdc_switch_tmax(const t_switch_inf& switch_inf) { + return switch_inf.R * switch_inf.Cout + switch_inf.Tdel; +} + +/******************************************************************** + * Set timing constraints between the inputs and outputs of a routing + * multiplexer in a Switch Block + *******************************************************************/ +static +void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& sb_module, + const RRGSB& rr_gsb, + const std::vector>& grids, + const std::vector& switches, + const e_side& output_node_side, + t_rr_node* output_rr_node) { + /* Validate file stream */ + check_file_handler(fp); + + VTR_ASSERT( ( CHANX == output_rr_node->type ) + || ( CHANY == output_rr_node->type )); + + /* Find the module port corresponding to the output rr_node */ + ModulePortId module_output_port = find_switch_block_module_chan_port(module_manager, + sb_module, + rr_gsb, + output_node_side, + output_rr_node, + OUT_PORT); + + /* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */ + std::vector input_rr_nodes; + for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { + input_rr_nodes.push_back(output_rr_node->drive_rr_nodes[iedge]); + } + + std::vector module_input_ports = find_switch_block_module_input_ports(module_manager, + sb_module, + rr_gsb, + grids, + input_rr_nodes); + + /* Find timing constraints for each path (edge) */ + std::map switch_delays; + for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { + /* Get the switch delay */ + int switch_id = output_rr_node->drive_switches[iedge]; + switch_delays[module_input_ports[iedge]] = find_pnr_sdc_switch_tmax(switches[switch_id]); + } + + /* Find the starting points */ + for (const ModulePortId& module_input_port : module_input_ports) { + /* Constrain a path */ + print_pnr_sdc_constrain_module_port2port_timing(fp, + module_manager, sb_module, + module_input_port, module_output_port, + switch_delays[module_input_port]); + } +} + +/******************************************************************** + * Set timing constraints between the inputs and outputs of SBs, + * which are connected by routing multiplexers with the given delays + * specified in architectural XML file + * + * To enable block by block timing constraining, we generate the SDC + * file for each unique SB module + *******************************************************************/ +static +void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const RRGSB& rr_gsb) { + + /* Create the file name for Verilog netlist */ + vtr::Point gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); + std::string sdc_fname(sdc_dir + generate_switch_block_module_name(gsb_coordinate) + std::string(SDC_FILE_NAME_POSTFIX)); + + /* Create the file stream */ + std::fstream fp; + fp.open(sdc_fname, std::fstream::out | std::fstream::trunc); + + /* Validate file stream */ + check_file_handler(fp); + + std::string sb_module_name = generate_switch_block_module_name(gsb_coordinate); + ModuleId sb_module = module_manager.find_module(sb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); + + /* Generate the descriptions*/ + print_sdc_file_header(fp, std::string("Constrain timing of Switch Block " + sb_module_name + " for PnR")); + + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) { + t_rr_node* chan_rr_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack); + /* We only care the output port and it should indicate a SB mux */ + if (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { + continue; + } + /* Constrain thru wires */ + if (false != rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack)) { + continue; + } + /* This is a MUX, constrain all the paths from an input to an output */ + print_pnr_sdc_constrain_sb_mux_timing(fp, + module_manager, sb_module, + rr_gsb, + grids, switches, + side_manager.get_side(), + chan_rr_node); + } + } + + /* Close file handler */ + fp.close(); +} + +/******************************************************************** + * Print SDC timing constraints for Switch blocks + * This function is designed for flatten routing hierarchy + *******************************************************************/ +void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb) { + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for constrain Switch Block timing for P&R flow..."); + + /* Start time count */ + clock_t t_start = clock(); + + /* Get the range of SB array */ + DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range(); + /* Go for each SB */ + for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { + const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); + print_pnr_sdc_constrain_sb_timing(sdc_dir, + module_manager, + grids, switches, + rr_gsb); + } + } + + /* 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); +} + +/******************************************************************** + * Print SDC timing constraints for Switch blocks + * This function is designed for compact routing hierarchy + *******************************************************************/ +void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb) { + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for constrain Switch Block timing for P&R flow..."); + + /* Start time count */ + clock_t t_start = clock(); + + for (size_t isb = 0; isb < L_device_rr_gsb.get_num_sb_unique_module(); ++isb) { + const RRGSB& rr_gsb = L_device_rr_gsb.get_sb_unique_module(isb); + print_pnr_sdc_constrain_sb_timing(sdc_dir, + module_manager, + grids, switches, + rr_gsb); + } + + /* 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); +} + +/******************************************************************** + * Set timing constraints between the inputs and outputs of a routing + * multiplexer in a Connection Block + *******************************************************************/ +static +void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& cb_module, + const RRGSB& rr_gsb, + const t_rr_type& cb_type, + const std::vector>& grids, + const std::vector& switches, + t_rr_node* output_rr_node) { + /* Validate file stream */ + check_file_handler(fp); + + VTR_ASSERT(IPIN == output_rr_node->type); + + /* Find the module port corresponding to the output rr_node */ + ModulePortId module_output_port = find_connection_block_module_ipin_port(module_manager, + cb_module, + rr_gsb, + grids, output_rr_node); + + /* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */ + std::vector input_rr_nodes; + for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { + input_rr_nodes.push_back(output_rr_node->drive_rr_nodes[iedge]); + } + + std::vector module_input_ports = find_connection_block_module_input_ports(module_manager, + cb_module, + rr_gsb, + cb_type, + input_rr_nodes); + + /* Find timing constraints for each path (edge) */ + std::map switch_delays; + for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { + /* Get the switch delay */ + int switch_id = output_rr_node->drive_switches[iedge]; + switch_delays[module_input_ports[iedge]] = find_pnr_sdc_switch_tmax(switches[switch_id]); + } + + /* Find the starting points */ + for (const ModulePortId& module_input_port : module_input_ports) { + /* Constrain a path */ + print_pnr_sdc_constrain_module_port2port_timing(fp, + module_manager, cb_module, + module_input_port, module_output_port, + switch_delays[module_input_port]); + } +} + + +/******************************************************************** + * Print SDC timing constraints for a Connection block + * This function is designed for compact routing hierarchy + *******************************************************************/ +static +void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const RRGSB& rr_gsb, + const t_rr_type& cb_type, + const std::vector>& grids, + const std::vector& switches) { + /* Create the netlist */ + vtr::Point gsb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); + + /* Find the module name and create a SDC file for it */ + std::string sdc_fname(sdc_dir + generate_connection_block_module_name(cb_type, gsb_coordinate) + std::string(SDC_FILE_NAME_POSTFIX)); + + /* Create the file stream */ + std::fstream fp; + fp.open(sdc_fname, std::fstream::out | std::fstream::trunc); + + /* Validate file stream */ + check_file_handler(fp); + + std::string cb_module_name = generate_connection_block_module_name(cb_type, gsb_coordinate); + ModuleId cb_module = module_manager.find_module(cb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(cb_module)); + + /* Generate the descriptions*/ + print_sdc_file_header(fp, std::string("Constrain timing of Connection Block " + cb_module_name + " for PnR")); + + std::vector cb_sides = rr_gsb.get_cb_ipin_sides(cb_type); + + for (size_t side = 0; side < cb_sides.size(); ++side) { + enum e_side cb_ipin_side = cb_sides[side]; + Side side_manager(cb_ipin_side); + for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) { + t_rr_node* ipin_rr_node = rr_gsb.get_ipin_node(cb_ipin_side, inode); + print_pnr_sdc_constrain_cb_mux_timing(fp, + module_manager, cb_module, + rr_gsb, cb_type, + grids, switches, + ipin_rr_node); + } + } + + /* Close file handler */ + fp.close(); +} + +/******************************************************************** + * Iterate over all the connection blocks in a device + * and print SDC file for each of them + *******************************************************************/ +static +void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const std::vector>& grids, + const std::vector& switches, + const t_rr_type& cb_type) { + /* Build unique X-direction connection block modules */ + DeviceCoordinator cb_range = L_device_rr_gsb.get_gsb_range(); + + for (size_t ix = 0; ix < cb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < cb_range.get_y(); ++iy) { + /* Check if the connection block exists in the device! + * Some of them do NOT exist due to heterogeneous blocks (height > 1) + * We will skip those modules + */ + const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); + if (false == rr_gsb.is_cb_exist(cb_type)) { + continue; + } + print_pnr_sdc_constrain_cb_timing(sdc_dir, + module_manager, + rr_gsb, + cb_type, + grids, switches); + + } + } +} + +/******************************************************************** + * Iterate over all the connection blocks in a device + * and print SDC file for each of them + *******************************************************************/ +void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const std::vector>& grids, + const std::vector& switches) { + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for constrain Connection Block timing for P&R flow..."); + + /* Start time count */ + clock_t t_start = clock(); + + print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager, + L_device_rr_gsb, + grids, + switches, + CHANX); + + print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager, + L_device_rr_gsb, + grids, + switches, + CHANY); + + /* 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); +} + +/******************************************************************** + * Print SDC timing constraints for Connection blocks + * This function is designed for compact routing hierarchy + *******************************************************************/ +void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb) { + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for constrain Connection Block timing for P&R flow..."); + + /* Start time count */ + clock_t t_start = clock(); + + /* Print SDC for unique X-direction connection block modules */ + for (size_t icb = 0; icb < L_device_rr_gsb.get_num_cb_unique_module(CHANX); ++icb) { + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(CHANX, icb); + print_pnr_sdc_constrain_cb_timing(sdc_dir, + module_manager, + unique_mirror, + CHANX, + grids, switches); + } + + /* Print SDC for unique Y-direction connection block modules */ + for (size_t icb = 0; icb < L_device_rr_gsb.get_num_cb_unique_module(CHANY); ++icb) { + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(CHANY, icb); + print_pnr_sdc_constrain_cb_timing(sdc_dir, + module_manager, + unique_mirror, + CHANY, + grids, switches); + } + + /* 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); +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.h new file mode 100644 index 000000000..c28bfbe26 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.h @@ -0,0 +1,34 @@ +#ifndef PNR_SDC_ROUTING_WRITER_H +#define PNR_SDC_ROUTING_WRITER_H + +#include +#include +#include "module_manager.h" +#include "rr_blocks.h" +#include "vpr_types.h" + +void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb); + +void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb); + +void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const std::vector>& grids, + const std::vector& switches); + +void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + const std::vector>& grids, + const std::vector& switches, + const DeviceRRGSB& L_device_rr_gsb); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp index 70b8f00ab..fcc9f2b2b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp @@ -21,10 +21,9 @@ #include "fpga_x2p_naming.h" #include "fpga_x2p_utils.h" -#include "build_routing_module_utils.h" - #include "sdc_writer_naming.h" #include "sdc_writer_utils.h" +#include "pnr_sdc_routing_writer.h" #include "pnr_sdc_writer.h" /******************************************************************** @@ -430,423 +429,6 @@ void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::strin run_time_sec); } -/******************************************************************** - * Find the timing constraints between the inputs and outputs of a routing - * multiplexer in a Switch Block - *******************************************************************/ -static -float find_pnr_sdc_switch_tmax(const t_switch_inf& switch_inf) { - return switch_inf.R * switch_inf.Cout + switch_inf.Tdel; -} - -/******************************************************************** - * Set timing constraints between the inputs and outputs of a routing - * multiplexer in a Switch Block - *******************************************************************/ -static -void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp, - const ModuleManager& module_manager, - const ModuleId& sb_module, - const RRGSB& rr_gsb, - const std::vector>& grids, - const std::vector& switches, - const e_side& output_node_side, - t_rr_node* output_rr_node) { - /* Validate file stream */ - check_file_handler(fp); - - VTR_ASSERT( ( CHANX == output_rr_node->type ) - || ( CHANY == output_rr_node->type )); - - /* Find the module port corresponding to the output rr_node */ - ModulePortId module_output_port = find_switch_block_module_chan_port(module_manager, - sb_module, - rr_gsb, - output_node_side, - output_rr_node, - OUT_PORT); - - /* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */ - std::vector input_rr_nodes; - for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { - input_rr_nodes.push_back(output_rr_node->drive_rr_nodes[iedge]); - } - - std::vector module_input_ports = find_switch_block_module_input_ports(module_manager, - sb_module, - rr_gsb, - grids, - input_rr_nodes); - - /* Find timing constraints for each path (edge) */ - std::map switch_delays; - for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { - /* Get the switch delay */ - int switch_id = output_rr_node->drive_switches[iedge]; - switch_delays[module_input_ports[iedge]] = find_pnr_sdc_switch_tmax(switches[switch_id]); - } - - /* Find the starting points */ - for (const ModulePortId& module_input_port : module_input_ports) { - /* Constrain a path */ - print_pnr_sdc_constrain_module_port2port_timing(fp, - module_manager, sb_module, - module_input_port, module_output_port, - switch_delays[module_input_port]); - } -} - -/******************************************************************** - * Set timing constraints between the inputs and outputs of SBs, - * which are connected by routing multiplexers with the given delays - * specified in architectural XML file - * - * To enable block by block timing constraining, we generate the SDC - * file for each unique SB module - *******************************************************************/ -static -void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir, - const ModuleManager& module_manager, - const std::vector>& grids, - const std::vector& switches, - const RRGSB& rr_gsb) { - - /* Create the file name for Verilog netlist */ - vtr::Point gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); - std::string sdc_fname(sdc_dir + generate_switch_block_module_name(gsb_coordinate) + std::string(SDC_FILE_NAME_POSTFIX)); - - /* Create the file stream */ - std::fstream fp; - fp.open(sdc_fname, std::fstream::out | std::fstream::trunc); - - /* Validate file stream */ - check_file_handler(fp); - - std::string sb_module_name = generate_switch_block_module_name(gsb_coordinate); - ModuleId sb_module = module_manager.find_module(sb_module_name); - VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); - - /* Generate the descriptions*/ - print_sdc_file_header(fp, std::string("Constrain timing of Switch Block " + sb_module_name + " for PnR")); - - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - Side side_manager(side); - for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) { - t_rr_node* chan_rr_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack); - /* We only care the output port and it should indicate a SB mux */ - if (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { - continue; - } - /* Constrain thru wires */ - if (false != rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack)) { - continue; - } - /* This is a MUX, constrain all the paths from an input to an output */ - print_pnr_sdc_constrain_sb_mux_timing(fp, - module_manager, sb_module, - rr_gsb, - grids, switches, - side_manager.get_side(), - chan_rr_node); - } - } - - /* Close file handler */ - fp.close(); -} - -/******************************************************************** - * Print SDC timing constraints for Switch blocks - * This function is designed for flatten routing hierarchy - *******************************************************************/ -static -void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir, - const ModuleManager& module_manager, - const std::vector>& grids, - const std::vector& switches, - const DeviceRRGSB& L_device_rr_gsb) { - vpr_printf(TIO_MESSAGE_INFO, - "Generating SDC for constrain Switch Block timing for P&R flow..."); - - /* Start time count */ - clock_t t_start = clock(); - - /* Get the range of SB array */ - DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range(); - /* Go for each SB */ - for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { - for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { - const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); - print_pnr_sdc_constrain_sb_timing(sdc_dir, - module_manager, - grids, switches, - rr_gsb); - } - } - - /* 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); -} - -/******************************************************************** - * Print SDC timing constraints for Switch blocks - * This function is designed for compact routing hierarchy - *******************************************************************/ -static -void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir, - const ModuleManager& module_manager, - const std::vector>& grids, - const std::vector& switches, - const DeviceRRGSB& L_device_rr_gsb) { - vpr_printf(TIO_MESSAGE_INFO, - "Generating SDC for constrain Switch Block timing for P&R flow..."); - - /* Start time count */ - clock_t t_start = clock(); - - for (size_t isb = 0; isb < L_device_rr_gsb.get_num_sb_unique_module(); ++isb) { - const RRGSB& rr_gsb = L_device_rr_gsb.get_sb_unique_module(isb); - print_pnr_sdc_constrain_sb_timing(sdc_dir, - module_manager, - grids, switches, - rr_gsb); - } - - /* 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); -} - -/******************************************************************** - * Set timing constraints between the inputs and outputs of a routing - * multiplexer in a Connection Block - *******************************************************************/ -static -void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp, - const ModuleManager& module_manager, - const ModuleId& cb_module, - const RRGSB& rr_gsb, - const t_rr_type& cb_type, - const std::vector>& grids, - const std::vector& switches, - t_rr_node* output_rr_node) { - /* Validate file stream */ - check_file_handler(fp); - - VTR_ASSERT(IPIN == output_rr_node->type); - - /* Find the module port corresponding to the output rr_node */ - ModulePortId module_output_port = find_connection_block_module_ipin_port(module_manager, - cb_module, - rr_gsb, - grids, output_rr_node); - - /* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */ - std::vector input_rr_nodes; - for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { - input_rr_nodes.push_back(output_rr_node->drive_rr_nodes[iedge]); - } - - std::vector module_input_ports = find_connection_block_module_input_ports(module_manager, - cb_module, - rr_gsb, - cb_type, - input_rr_nodes); - - /* Find timing constraints for each path (edge) */ - std::map switch_delays; - for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { - /* Get the switch delay */ - int switch_id = output_rr_node->drive_switches[iedge]; - switch_delays[module_input_ports[iedge]] = find_pnr_sdc_switch_tmax(switches[switch_id]); - } - - /* Find the starting points */ - for (const ModulePortId& module_input_port : module_input_ports) { - /* Constrain a path */ - print_pnr_sdc_constrain_module_port2port_timing(fp, - module_manager, cb_module, - module_input_port, module_output_port, - switch_delays[module_input_port]); - } -} - - -/******************************************************************** - * Print SDC timing constraints for a Connection block - * This function is designed for compact routing hierarchy - *******************************************************************/ -static -void print_pnr_sdc_constrain_cb_timing(const std::string& sdc_dir, - const ModuleManager& module_manager, - const RRGSB& rr_gsb, - const t_rr_type& cb_type, - const std::vector>& grids, - const std::vector& switches) { - /* Create the netlist */ - vtr::Point gsb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); - - /* Find the module name and create a SDC file for it */ - std::string sdc_fname(sdc_dir + generate_connection_block_module_name(cb_type, gsb_coordinate) + std::string(SDC_FILE_NAME_POSTFIX)); - - /* Create the file stream */ - std::fstream fp; - fp.open(sdc_fname, std::fstream::out | std::fstream::trunc); - - /* Validate file stream */ - check_file_handler(fp); - - std::string cb_module_name = generate_connection_block_module_name(cb_type, gsb_coordinate); - ModuleId cb_module = module_manager.find_module(cb_module_name); - VTR_ASSERT(true == module_manager.valid_module_id(cb_module)); - - /* Generate the descriptions*/ - print_sdc_file_header(fp, std::string("Constrain timing of Connection Block " + cb_module_name + " for PnR")); - - std::vector cb_sides = rr_gsb.get_cb_ipin_sides(cb_type); - - for (size_t side = 0; side < cb_sides.size(); ++side) { - enum e_side cb_ipin_side = cb_sides[side]; - Side side_manager(cb_ipin_side); - for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) { - t_rr_node* ipin_rr_node = rr_gsb.get_ipin_node(cb_ipin_side, inode); - print_pnr_sdc_constrain_cb_mux_timing(fp, - module_manager, cb_module, - rr_gsb, cb_type, - grids, switches, - ipin_rr_node); - } - } - - /* Close file handler */ - fp.close(); -} - -/******************************************************************** - * Iterate over all the connection blocks in a device - * and print SDC file for each of them - *******************************************************************/ -static -void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir, - const ModuleManager& module_manager, - const DeviceRRGSB& L_device_rr_gsb, - const std::vector>& grids, - const std::vector& switches, - const t_rr_type& cb_type) { - /* Build unique X-direction connection block modules */ - DeviceCoordinator cb_range = L_device_rr_gsb.get_gsb_range(); - - for (size_t ix = 0; ix < cb_range.get_x(); ++ix) { - for (size_t iy = 0; iy < cb_range.get_y(); ++iy) { - /* Check if the connection block exists in the device! - * Some of them do NOT exist due to heterogeneous blocks (height > 1) - * We will skip those modules - */ - const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); - if (false == rr_gsb.is_cb_exist(cb_type)) { - continue; - } - print_pnr_sdc_constrain_cb_timing(sdc_dir, - module_manager, - rr_gsb, - cb_type, - grids, switches); - - } - } -} - -/******************************************************************** - * Iterate over all the connection blocks in a device - * and print SDC file for each of them - *******************************************************************/ -static -void print_pnr_sdc_flatten_routing_constrain_cb_timing(const std::string& sdc_dir, - const ModuleManager& module_manager, - const DeviceRRGSB& L_device_rr_gsb, - const std::vector>& grids, - const std::vector& switches) { - vpr_printf(TIO_MESSAGE_INFO, - "Generating SDC for constrain Connection Block timing for P&R flow..."); - - /* Start time count */ - clock_t t_start = clock(); - - print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager, - L_device_rr_gsb, - grids, - switches, - CHANX); - - print_pnr_sdc_flatten_routing_constrain_cb_timing(sdc_dir, module_manager, - L_device_rr_gsb, - grids, - switches, - CHANY); - - /* 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); -} - -/******************************************************************** - * Print SDC timing constraints for Connection blocks - * This function is designed for compact routing hierarchy - *******************************************************************/ -static -void print_pnr_sdc_compact_routing_constrain_cb_timing(const std::string& sdc_dir, - const ModuleManager& module_manager, - const std::vector>& grids, - const std::vector& switches, - const DeviceRRGSB& L_device_rr_gsb) { - vpr_printf(TIO_MESSAGE_INFO, - "Generating SDC for constrain Connection Block timing for P&R flow..."); - - /* Start time count */ - clock_t t_start = clock(); - - /* Print SDC for unique X-direction connection block modules */ - for (size_t icb = 0; icb < L_device_rr_gsb.get_num_cb_unique_module(CHANX); ++icb) { - const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(CHANX, icb); - print_pnr_sdc_constrain_cb_timing(sdc_dir, - module_manager, - unique_mirror, - CHANX, - grids, switches); - } - - /* Print SDC for unique Y-direction connection block modules */ - for (size_t icb = 0; icb < L_device_rr_gsb.get_num_cb_unique_module(CHANY); ++icb) { - const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(CHANY, icb); - print_pnr_sdc_constrain_cb_timing(sdc_dir, - module_manager, - unique_mirror, - CHANY, - grids, switches); - } - - /* 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 From bcd823726354c85e47746689b00f10d25f7a181c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 9 Nov 2019 20:57:54 -0700 Subject: [PATCH 54/68] refactored grid PnR SDC generator --- .../backend_assistant/pnr_sdc_grid_writer.cpp | 361 ++++++++++++++++++ .../backend_assistant/pnr_sdc_grid_writer.h | 11 + .../pnr_sdc_routing_writer.cpp | 10 +- .../backend_assistant/pnr_sdc_writer.cpp | 9 +- .../backend_assistant/sdc_writer_utils.cpp | 44 ++- .../backend_assistant/sdc_writer_utils.h | 10 +- vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c | 2 +- 7 files changed, 424 insertions(+), 23 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_grid_writer.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_grid_writer.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_grid_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_grid_writer.cpp new file mode 100644 index 000000000..8032daca4 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_grid_writer.cpp @@ -0,0 +1,361 @@ +/******************************************************************** + * 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 grid + * (CLBs, heterogeneous blocks etc.) + * + * 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 "vtr_assert.h" +#include "device_port.h" + +#include "util.h" +#include "mux_utils.h" + +#include "fpga_x2p_reserved_words.h" +#include "fpga_x2p_naming.h" +#include "fpga_x2p_utils.h" +#include "fpga_x2p_pbtypes_utils.h" + +#include "sdc_writer_naming.h" +#include "sdc_writer_utils.h" +#include "pnr_sdc_grid_writer.h" + +#include "globals.h" + +/******************************************************************** + * Print pin-to-pin timing constraints for a given interconnection + * at an output port of a pb_graph node + *******************************************************************/ +static +void print_pnr_sdc_constrain_pb_pin_interc_timing(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const e_side& border_side, + t_pb_graph_pin* des_pb_graph_pin, + t_mode* physical_mode) { + + /* Validate file stream */ + check_file_handler(fp); + + /* 1. identify pin interconnection type, + * 2. Identify the number of fan-in (Consider interconnection edges of only selected mode) + * 3. Print SDC timing constraints + */ + int fan_in = 0; + t_interconnect* cur_interc = NULL; + find_interc_fan_in_des_pb_graph_pin(des_pb_graph_pin, physical_mode, &cur_interc, &fan_in); + if ((NULL == cur_interc) || (0 == fan_in)) { + /* No interconnection matched */ + return; + } + + /* Print pin-to-pin SDC contraint here */ + /* For more than one mode defined, the direct interc has more than one input_edge , + * We need to find which edge is connected the pin we want + */ + for (int iedge = 0; iedge < des_pb_graph_pin->num_input_edges; iedge++) { + if (cur_interc != des_pb_graph_pin->input_edges[iedge]->interconnect) { + continue; + } + + /* Source pin, node, pb_type*/ + t_pb_graph_pin* src_pb_graph_pin = des_pb_graph_pin->input_edges[iedge]->input_pins[0]; + t_pb_graph_node* src_pb_graph_node = src_pb_graph_pin->parent_node; + /* Des pin, node, pb_type */ + t_pb_graph_node* des_pb_graph_node = des_pb_graph_pin->parent_node; + + /* Find the src module in module manager */ + std::string src_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side); + std::string src_module_name = generate_physical_block_module_name(src_module_name_prefix, src_pb_graph_pin->parent_node->pb_type); + ModuleId src_module = module_manager.find_module(src_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(src_module)); + + ModulePortId src_module_port_id = module_manager.find_module_port(src_module, generate_pb_type_port_name(src_pb_graph_pin->port)); + VTR_ASSERT(true == module_manager.valid_module_port_id(src_module, src_module_port_id)); + + /* Generate the name of the des instance name + * If des module is not the parent module, it is a child module. + * We should find the instance id + */ + std::string src_instance_name = src_module_name; + if (parent_module != src_module) { + src_instance_name = module_manager.module_name(parent_module) + std::string("/"); + /* Instance id is actually the placement index */ + size_t instance_id = src_pb_graph_node->placement_index; + if (true == module_manager.instance_name(parent_module, src_module, instance_id).empty()) { + src_instance_name += src_module_name; + src_instance_name += "_"; + src_instance_name += std::to_string(instance_id); + src_instance_name += "_"; + } else { + src_instance_name += module_manager.instance_name(parent_module, src_module, instance_id); + } + } + + /* Generate src port information */ + BasicPort src_port = module_manager.module_port(src_module, src_module_port_id); + src_port.set_width(src_pb_graph_pin->pin_number, src_pb_graph_pin->pin_number); + + /* Find the des module in module manager */ + std::string des_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side); + std::string des_module_name = generate_physical_block_module_name(des_module_name_prefix, des_pb_graph_pin->parent_node->pb_type); + ModuleId des_module = module_manager.find_module(des_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(des_module)); + ModulePortId des_module_port_id = module_manager.find_module_port(des_module, generate_pb_type_port_name(des_pb_graph_pin->port)); + VTR_ASSERT(true == module_manager.valid_module_port_id(des_module, des_module_port_id)); + + /* Generate the name of the des instance name + * If des module is not the parent module, it is a child module. + * We should find the instance id + */ + std::string des_instance_name = des_module_name; + if (parent_module != des_module) { + des_instance_name = module_manager.module_name(parent_module) + std::string("/"); + /* Instance id is actually the placement index */ + size_t instance_id = des_pb_graph_node->placement_index; + if (true == module_manager.instance_name(parent_module, des_module, instance_id).empty()) { + des_instance_name += des_module_name; + des_instance_name += "_"; + des_instance_name += std::to_string(instance_id); + des_instance_name += "_"; + } else { + des_instance_name += module_manager.instance_name(parent_module, des_module, instance_id); + } + } + + /* Generate des port information */ + BasicPort des_port = module_manager.module_port(des_module, des_module_port_id); + des_port.set_width(des_pb_graph_pin->pin_number, des_pb_graph_pin->pin_number); + + /* Print a SDC timing constraint */ + print_pnr_sdc_constrain_max_delay(fp, + src_instance_name, + generate_sdc_port(src_port), + des_instance_name, + generate_sdc_port(des_port), + des_pb_graph_pin->input_edges[iedge]->delay_max); + } +} + +/******************************************************************** + * Print port-to-port timing constraints which source from + * an output port of a pb_graph node + *******************************************************************/ +static +void print_pnr_sdc_constrain_pb_interc_timing(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const e_side& border_side, + t_pb_graph_node* des_pb_graph_node, + const e_spice_pb_port_type& pb_port_type, + t_mode* physical_mode) { + /* Validate file stream */ + check_file_handler(fp); + + switch (pb_port_type) { + case SPICE_PB_PORT_INPUT: { + for (int iport = 0; iport < des_pb_graph_node->num_input_ports; ++iport) { + 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, module_manager, parent_module, border_side, + &(des_pb_graph_node->input_pins[iport][ipin]), + physical_mode); + } + } + break; + } + case SPICE_PB_PORT_OUTPUT: { + 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, module_manager, parent_module, border_side, + &(des_pb_graph_node->output_pins[iport][ipin]), + physical_mode); + } + } + break; + } + case SPICE_PB_PORT_CLOCK: { + /* Do NOT constrain clock here, it should be handled by Clock Tree Synthesis */ + break; + } + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid pb port type!\n", + __FILE__, __LINE__); + exit(1); + } +} + +/******************************************************************** + * This function will generate a SDC file for each pb_type, + * constraining the pin-to-pin timing between + * 1. input port of parent_pb_graph_node and input port of child_pb_graph_nodes + * 2. output port of parent_pb_graph_node and output port of child_pb_graph_nodes + * 3. output port of child_pb_graph_node and input port of child_pb_graph_nodes + *******************************************************************/ +static +void print_pnr_sdc_constrain_pb_graph_node_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + t_pb_graph_node* parent_pb_graph_node, + const int& physical_mode_index, + const e_side& border_side) { + + /* Get the pb_type definition related to the node */ + t_pb_type* physical_pb_type = parent_pb_graph_node->pb_type; + std::string pb_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side); + std::string pb_module_name = generate_physical_block_module_name(pb_module_name_prefix, physical_pb_type); + + /* Find the pb module in module manager */ + ModuleId pb_module = module_manager.find_module(pb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(pb_module)); + + /* Create the file name for SDC */ + std::string sdc_fname(sdc_dir + pb_module_name + std::string(SDC_FILE_NAME_POSTFIX)); + + /* 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("Timing constraints for Grid " + pb_module_name + " in PnR")); + + t_mode* physical_mode = &(parent_pb_graph_node->pb_type->modes[physical_mode_index]); + + /* 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 + * /|\ + * | + * input_pins, edges, output_pins + */ + print_pnr_sdc_constrain_pb_interc_timing(fp, module_manager, pb_module, border_side, + parent_pb_graph_node, + SPICE_PB_PORT_OUTPUT, + physical_mode); + + /* We check input_pins of child_pb_graph_node and its the input_edges + * Built the interconnections between inputs of cur_pb_graph_node and inputs of child_pb_graph_node + * cur_pb_graph_node.input_pins -----------------> child_pb_graph_node.input_pins + * /|\ + * | + * input_pins, edges, output_pins + */ + for (int ipb = 0; ipb < physical_mode->num_pb_type_children; ++ipb) { + for (int jpb = 0; jpb < physical_mode->pb_type_children[ipb].num_pb; ++jpb) { + 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, module_manager, pb_module, border_side, + child_pb_graph_node, + SPICE_PB_PORT_INPUT, + physical_mode); + /* Do NOT constrain clock here, it should be handled by Clock Tree Synthesis */ + } + } + + /* Close file handler */ + fp.close(); +} + +/******************************************************************** + * Recursively print SDC timing constraints for a pb_type + * This function will generate a SDC file for each pb_type, + * constraining the pin-to-pin timing + *******************************************************************/ +static +void rec_print_pnr_sdc_constrain_pb_graph_timing(const std::string& sdc_dir, + const ModuleManager& module_manager, + t_pb_graph_node* parent_pb_graph_node, + const e_side& border_side) { + /* Validate pb_graph node */ + if (NULL == parent_pb_graph_node) { + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid parent_pb_graph_node.\n", + __FILE__, __LINE__); + exit(1); + } + + /* Get the pb_type */ + t_pb_type* parent_pb_type = parent_pb_graph_node->pb_type; + + /* No need to constrain the primitive node */ + if (TRUE == is_primitive_pb_type(parent_pb_type)) { + return; + } + + /* Note we only go through the graph through the physical modes. + * which we build the modules + */ + int physical_mode_index = find_pb_type_physical_mode_index((*parent_pb_type)); + + /* Write a SDC file for this pb_type */ + print_pnr_sdc_constrain_pb_graph_node_timing(sdc_dir, module_manager, + parent_pb_graph_node, physical_mode_index, + border_side); + + /* Go recursively to the lower level in the pb_graph + * 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 < parent_pb_type->modes[physical_mode_index].num_pb_type_children; ++ipb) { + rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, module_manager, + &(parent_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ipb][0]), + border_side); + } +} + +/******************************************************************** + * Top-level function to print timing constraints for pb_types + *******************************************************************/ +void print_pnr_sdc_constrain_grid_timing(const std::string& sdc_dir, + const ModuleManager& module_manager) { + + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for constraining grid timing for P&R flow..."); + + /* Start time count */ + clock_t t_start = clock(); + + for (int itype = 0; itype < num_types; itype++) { + /* Bypass EMPTY types */ + if (EMPTY_TYPE == &type_descriptors[itype]) { + continue; + } + + /* For IO_TYPE, we have four types of I/Os */ + if (IO_TYPE == &type_descriptors[itype]) { + /* Special for I/O block, generate one module for each border side */ + for (int iside = 0; iside < NUM_SIDES; iside++) { + Side side_manager(iside); + rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, module_manager, + type_descriptors[itype].pb_graph_head, + side_manager.get_side()); + } + } else if (FILL_TYPE == &type_descriptors[itype]) { + /* For CLB */ + rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, module_manager, + type_descriptors[itype].pb_graph_head, + NUM_SIDES); + } else { + /* For heterogenenous blocks */ + rec_print_pnr_sdc_constrain_pb_graph_timing(sdc_dir, module_manager, + type_descriptors[itype].pb_graph_head, + NUM_SIDES); + } + } + + /* 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); +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_grid_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_grid_writer.h new file mode 100644 index 000000000..d27b292ef --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_grid_writer.h @@ -0,0 +1,11 @@ +#ifndef PNR_SDC_GRID_WRITER_H +#define PNR_SDC_GRID_WRITER_H + +#include +#include +#include "vpr_types.h" + +void print_pnr_sdc_constrain_grid_timing(const std::string& sdc_dir, + const ModuleManager& module_manager); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp index 9fbe46b4c..13bc17d1c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp @@ -85,8 +85,9 @@ void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp, for (const ModulePortId& module_input_port : module_input_ports) { /* Constrain a path */ print_pnr_sdc_constrain_module_port2port_timing(fp, - module_manager, sb_module, - module_input_port, module_output_port, + module_manager, + sb_module, module_input_port, + sb_module, module_output_port, switch_delays[module_input_port]); } } @@ -267,8 +268,9 @@ void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp, for (const ModulePortId& module_input_port : module_input_ports) { /* Constrain a path */ print_pnr_sdc_constrain_module_port2port_timing(fp, - module_manager, cb_module, - module_input_port, module_output_port, + module_manager, + cb_module, module_input_port, + cb_module, module_output_port, switch_delays[module_input_port]); } } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp index fcc9f2b2b..b5f58bf90 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp @@ -24,6 +24,7 @@ #include "sdc_writer_naming.h" #include "sdc_writer_utils.h" #include "pnr_sdc_routing_writer.h" +#include "pnr_sdc_grid_writer.h" #include "pnr_sdc_writer.h" /******************************************************************** @@ -517,11 +518,9 @@ void print_pnr_sdc(const SdcOption& sdc_options, } } - /* TODO: Output routing constraints for Programmable blocks */ - /* + /* Output Timing constraints for Programmable blocks */ if (true == sdc_options.constrain_grid()) { - verilog_generate_sdc_constrain_pb_types(cur_sram_orgz_info, - sdc_dir); + print_pnr_sdc_constrain_grid_timing(sdc_options.sdc_dir(), + module_manager); } - */ } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp index 6a74c290d..13e3e6ba0 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp @@ -53,29 +53,49 @@ std::string generate_sdc_port(const BasicPort& port) { } /******************************************************************** - * Constrain a path between two ports of a module with a given timing value + * Constrain a path between two ports of a module with a given maximum timing value *******************************************************************/ -void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp, - const ModuleManager& module_manager, - const ModuleId& module_id, - const ModulePortId& module_input_port_id, - const ModulePortId& module_output_port_id, - const float& tmax) { +void print_pnr_sdc_constrain_max_delay(std::fstream& fp, + const std::string& src_instance_name, + const std::string& src_port_name, + const std::string& des_instance_name, + const std::string& des_port_name, + const float& delay) { /* Validate file stream */ check_file_handler(fp); fp << "set_max_delay"; fp << " -from "; - fp << module_manager.module_name(module_id) << "/"; - fp << generate_sdc_port(module_manager.module_port(module_id, module_input_port_id)); + fp << src_instance_name << "/"; + fp << src_port_name; fp << " -to "; - fp << module_manager.module_name(module_id) << "/"; - fp << generate_sdc_port(module_manager.module_port(module_id, module_output_port_id)); + fp << des_instance_name << "/"; + fp << des_port_name; - fp << " " << std::setprecision(10) << tmax; + fp << " " << std::setprecision(10) << delay; fp << std::endl; } + +/******************************************************************** + * Constrain a path between two ports of a module with a given timing value + * Note: this function uses set_max_delay !!! + *******************************************************************/ +void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& input_parent_module_id, + const ModulePortId& module_input_port_id, + const ModuleId& output_parent_module_id, + const ModulePortId& module_output_port_id, + const float& tmax) { + print_pnr_sdc_constrain_max_delay(fp, + module_manager.module_name(input_parent_module_id), + generate_sdc_port(module_manager.module_port(input_parent_module_id, module_input_port_id)), + module_manager.module_name(output_parent_module_id), + generate_sdc_port(module_manager.module_port(output_parent_module_id, module_output_port_id)), + tmax); + +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h index d4c2ae860..25684ca96 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h @@ -11,10 +11,18 @@ void print_sdc_file_header(std::fstream& fp, std::string generate_sdc_port(const BasicPort& port); +void print_pnr_sdc_constrain_max_delay(std::fstream& fp, + const std::string& src_instance_name, + const std::string& src_port_name, + const std::string& des_instance_name, + const std::string& des_port_name, + const float& delay); + void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp, const ModuleManager& module_manager, - const ModuleId& module_id, + const ModuleId& input_parent_module_id, const ModulePortId& module_input_port_id, + const ModuleId& output_parent_module_id, const ModulePortId& module_output_port_id, const float& tmax); 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 a254d4824..8fa4709f1 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 @@ -159,7 +159,7 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, /* 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, - grids, rr_switches, device_rr_gsb, + grids, rr_switches, device_rr_gsb, module_manager, mux_lib, Arch.spice->circuit_lib, global_ports, TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy); From 1f368abfbeb7c2368a4c4aac388293ed6f636bf0 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 10 Nov 2019 15:40:54 -0700 Subject: [PATCH 55/68] refactoring analysis SDC generation --- .../backend_assistant/analysis_sdc_writer.cpp | 260 ++++++++++++++++++ .../backend_assistant/analysis_sdc_writer.h | 22 ++ .../fpga_x2p/backend_assistant/sdc_api.cpp | 15 + .../SRC/fpga_x2p/backend_assistant/sdc_api.h | 4 + .../backend_assistant/sdc_writer_naming.h | 2 + .../backend_assistant/sdc_writer_utils.cpp | 71 +++++ .../backend_assistant/sdc_writer_utils.h | 13 + vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c | 1 + 8 files changed, 388 insertions(+) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp new file mode 100644 index 000000000..4a5fe91c3 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp @@ -0,0 +1,260 @@ +/******************************************************************** + * This file includes functions that are used to output a SDC file + * that constrain a FPGA fabric (P&Red netlist) using a benchmark + *******************************************************************/ +#include +#include +#include + +#include "vtr_assert.h" +#include "device_port.h" + +#include "util.h" +#include "mux_utils.h" + +#include "fpga_x2p_naming.h" +#include "fpga_x2p_utils.h" +#include "fpga_x2p_benchmark_utils.h" + +#include "sdc_writer_naming.h" +#include "sdc_writer_utils.h" + +#include "analysis_sdc_writer.h" + +/******************************************************************** + * Generate SDC constaints for inputs and outputs + * We consider the top module in formal verification purpose here + * which is easier + *******************************************************************/ +static +void print_analysis_sdc_io_delays(std::fstream& fp, + const std::vector& L_logical_blocks, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, + const ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports, + const float& critical_path_delay) { + /* Validate the file stream */ + check_file_handler(fp); + + /* Print comments */ + fp << "##################################################" << std::endl; + fp << "# Create clock " << std::endl; + fp << "##################################################" << std::endl; + + /* Get clock port from the global port */ + std::vector operating_clock_ports; + for (const CircuitPortId& clock_port : global_ports) { + if (SPICE_MODEL_PORT_CLOCK != circuit_lib.port_type(clock_port)) { + continue; + } + /* We only constrain operating clock here! */ + if (true == circuit_lib.port_is_prog(clock_port)) { + continue; + } + + /* Update the operating port list */ + operating_clock_ports.push_back(BasicPort(circuit_lib.port_prefix(clock_port), circuit_lib.port_size(clock_port))); + } + + for (const BasicPort& operating_clock_port : operating_clock_ports) { + /* 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 << std::endl; + + /* Add an empty line as a splitter */ + fp << std::endl; + } + + /* There should be only one operating clock! + * TODO: this should be changed when developing multi-clock support!!! + */ + VTR_ASSERT(1 == operating_clock_ports.size()); + + /* In this function, we support only 1 type of I/Os */ + VTR_ASSERT(1 == module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT).size()); + BasicPort module_io_port = module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)[0]; + + /* Keep tracking which I/Os have been used */ + std::vector io_used(module_io_port.get_width(), false); + + /* Print comments */ + fp << "##################################################" << std::endl; + fp << "# Create input and output delays for used I/Os " << std::endl; + fp << "##################################################" << std::endl; + + for (const t_logical_block& io_lb : L_logical_blocks) { + /* We only care I/O logical blocks !*/ + if ( (VPACK_INPAD != io_lb.type) && (VPACK_OUTPAD != io_lb.type) ) { + continue; + } + + /* clock net or constant generator should be disabled in timing analysis */ + if (TRUE == io_lb.is_clock) { + continue; + } + + /* Find the index of the mapped GPIO in top-level FPGA fabric */ + size_t io_index = find_benchmark_io_index(io_lb, device_size, L_grids, L_blocks); + + /* Ensure that IO index is in range */ + BasicPort module_mapped_io_port = module_io_port; + /* Set the port pin index */ + VTR_ASSERT(io_index < module_mapped_io_port.get_width()); + module_mapped_io_port.set_width(io_index, io_index); + + /* For input I/O, we set an input delay constraint correlated to the operating clock + * For output I/O, we set an output delay constraint correlated to the operating clock + */ + if (VPACK_INPAD == io_lb.type) { + print_sdc_set_port_input_delay(fp, module_mapped_io_port, + operating_clock_ports[0], critical_path_delay); + } else { + VTR_ASSERT(VPACK_OUTPAD == io_lb.type); + print_sdc_set_port_output_delay(fp, module_mapped_io_port, + operating_clock_ports[0], critical_path_delay); + } + + /* Mark this I/O has been used/wired */ + io_used[io_index] = true; + } + + /* Add an empty line as a splitter */ + fp << std::endl; + + /* Print comments */ + fp << "##################################################" << std::endl; + fp << "# Disable timing for unused I/Os " << std::endl; + fp << "##################################################" << std::endl; + + /* Wire the unused iopads to a constant */ + for (size_t io_index = 0; io_index < io_used.size(); ++io_index) { + /* Bypass used iopads */ + if (true == io_used[io_index]) { + continue; + } + + /* Wire to a contant */ + BasicPort module_unused_io_port = module_io_port; + /* Set the port pin index */ + module_unused_io_port.set_width(io_index, io_index); + print_sdc_disable_port_timing(fp, module_unused_io_port); + } + + /* Add an empty line as a splitter */ + fp << std::endl; +} + +/******************************************************************** + * Top-level function outputs a SDC file + * that constrain a FPGA fabric (P&Red netlist) using a benchmark + *******************************************************************/ +void print_analysis_sdc(const std::string& sdc_dir, + const float& critical_path_delay, + const DeviceRRGSB& L_device_rr_gsb, + const std::vector& L_logical_blocks, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, + const ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports, + const bool& compact_routing_hierarchy) { + /* Create the file name for Verilog netlist */ + std::string sdc_fname(sdc_dir + std::string(SDC_ANALYSIS_FILE_NAME)); + + vpr_printf(TIO_MESSAGE_INFO, + "Generating SDC for Timing/Power analysis on the mapped FPGA: %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); + + /* Validate file stream */ + check_file_handler(fp); + + /* Generate the descriptions*/ + print_sdc_file_header(fp, std::string("Constrain for Timing/Power analysis on the mapped FPGA")); + + /* Find the top_module */ + ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name()); + VTR_ASSERT(true == module_manager.valid_module_id(top_module)); + + /* Create clock and set I/O ports with input/output delays */ + print_analysis_sdc_io_delays(fp, + L_logical_blocks, device_size, L_grids, L_blocks, + module_manager, top_module, + circuit_lib, global_ports, + critical_path_delay); + + /* TODO: Disable the timing for global ports */ + /* + verilog_generate_sdc_disable_global_ports(fp); + */ + + /* TODO: Disable the timing for configuration cells */ + /* + verilog_generate_sdc_disable_sram_orgz(fp, cur_sram_orgz_info); + */ + + /* TODO: Disable timing for un-used resources */ + /* Apply to Routing Channels */ + /* + if (TRUE == compact_routing_hierarchy) { + verilog_generate_sdc_disable_unused_routing_channels(fp, LL_nx, LL_ny); + } else { + verilog_generate_sdc_disable_unused_routing_channels(fp, LL_nx, LL_ny, + LL_num_rr_nodes, LL_rr_node, + LL_rr_node_indices); + } + */ + + /* TODO: Apply to Connection blocks */ + /* + if (TRUE == compact_routing_hierarchy) { + verilog_generate_sdc_disable_unused_cbs(fp, LL_nx, LL_ny, LL_device_rr_gsb); + verilog_generate_sdc_disable_unused_cbs_muxs(fp, LL_nx, LL_ny, LL_device_rr_gsb); + } else { + verilog_generate_sdc_disable_unused_cbs(fp, LL_nx, LL_ny); + verilog_generate_sdc_disable_unused_cbs_muxs(fp, LL_nx, LL_ny); + } + */ + + /* TODO: Apply to Switch blocks */ + /* + if (TRUE == compact_routing_hierarchy) { + verilog_generate_sdc_disable_unused_sbs(fp); + verilog_generate_sdc_disable_unused_sbs_muxs(fp); + } else { + verilog_generate_sdc_disable_unused_sbs(fp, LL_nx, LL_ny); + verilog_generate_sdc_disable_unused_sbs_muxs(fp, LL_nx, LL_ny); + } + */ + + /* TODO: Apply to Grids */ + /* + verilog_generate_sdc_disable_unused_grids(fp, LL_nx, LL_ny, LL_grid, LL_block); + verilog_generate_sdc_disable_unused_grids_muxs(fp, LL_nx, LL_ny, LL_grid, LL_block); + */ + + /* 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); +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h new file mode 100644 index 000000000..252c76c71 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h @@ -0,0 +1,22 @@ +#ifndef ANALYSIS_SDC_WRITER_H +#define ANALYSIS_SDC_WRITER_H + +#include +#include "vpr_types.h" +#include "rr_blocks.h" +#include "module_manager.h" +#include "bitstream_manager.h" + +void print_analysis_sdc(const std::string& sdc_dir, + const float& critical_path_delay, + const DeviceRRGSB& L_device_rr_gsb, + const std::vector& L_logical_blocks, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, + const ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports, + const bool& compact_routing_hierarchy); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp index 690e456c5..bf9f17858 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp @@ -3,6 +3,7 @@ *******************************************************************/ #include #include "pnr_sdc_writer.h" +#include "analysis_sdc_writer.h" #include "sdc_api.h" @@ -14,6 +15,10 @@ void fpga_sdc_generator(const SdcOption& sdc_options, const std::vector>& grids, const std::vector& switches, const DeviceRRGSB& L_device_rr_gsb, + const std::vector& L_logical_blocks, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, const ModuleManager& module_manager, const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, @@ -33,6 +38,16 @@ void fpga_sdc_generator(const SdcOption& sdc_options, compact_routing_hierarchy); } + if (true == sdc_options.generate_sdc_analysis()) { + print_analysis_sdc(sdc_options.sdc_dir(), + critical_path_delay, + L_device_rr_gsb, + L_logical_blocks, device_size, L_grids, L_blocks, + module_manager, + circuit_lib, global_ports, + compact_routing_hierarchy); + } + /* End time count */ clock_t t_end = clock(); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h index d53dc201a..02874e3a3 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h @@ -12,6 +12,10 @@ void fpga_sdc_generator(const SdcOption& sdc_options, const std::vector>& grids, const std::vector& switches, const DeviceRRGSB& L_device_rr_gsb, + const std::vector& L_logical_blocks, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, const ModuleManager& module_manager, const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h index e479f95d3..9a9f3af29 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_naming.h @@ -10,4 +10,6 @@ constexpr char* SDC_DISABLE_MUX_OUTPUTS_FILE_NAME = "disable_routing_multiplexer constexpr char* SDC_DISABLE_SB_OUTPUTS_FILE_NAME = "disable_sb_outputs.sdc"; constexpr char* SDC_CB_FILE_NAME = "cb.sdc"; +constexpr char* SDC_ANALYSIS_FILE_NAME = "fpga_top_analysis.sdc"; + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp index 13e3e6ba0..0613cac7a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.cpp @@ -99,3 +99,74 @@ void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp, tmax); } + +/******************************************************************** + * Disable timing for a port + *******************************************************************/ +void print_sdc_disable_port_timing(std::fstream& fp, + const BasicPort& port) { + /* Validate file stream */ + check_file_handler(fp); + + fp << "set_disable_timing "; + + fp << generate_sdc_port(port); + + fp << std::endl; +} + +/******************************************************************** + * Set the input delay for a port in SDC format + * Note that the input delay will be bounded by a clock port + *******************************************************************/ +void print_sdc_set_port_input_delay(std::fstream& fp, + const BasicPort& port, + const BasicPort& clock_port, + const float& delay) { + /* Validate file stream */ + check_file_handler(fp); + + fp << "set_input_delay "; + + fp << "-clock "; + + fp << generate_sdc_port(clock_port); + + fp << " -max "; + + fp << std::setprecision(10) << delay; + + fp << " "; + + fp << generate_sdc_port(port); + + fp << std::endl; +} + +/******************************************************************** + * Set the output delay for a port in SDC format + * Note that the output delay will be bounded by a clock port + *******************************************************************/ +void print_sdc_set_port_output_delay(std::fstream& fp, + const BasicPort& port, + const BasicPort& clock_port, + const float& delay) { + /* Validate file stream */ + check_file_handler(fp); + + fp << "set_output_delay "; + + fp << "-clock "; + + fp << generate_sdc_port(clock_port); + + fp << " -max "; + + fp << std::setprecision(10) << delay; + + fp << " "; + + fp << generate_sdc_port(port); + + fp << std::endl; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h index 25684ca96..9483f0379 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_writer_utils.h @@ -26,4 +26,17 @@ void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp, const ModulePortId& module_output_port_id, const float& tmax); +void print_sdc_disable_port_timing(std::fstream& fp, + const BasicPort& port); + +void print_sdc_set_port_input_delay(std::fstream& fp, + const BasicPort& port, + const BasicPort& clock_port, + const float& delay); + +void print_sdc_set_port_output_delay(std::fstream& fp, + const BasicPort& port, + const BasicPort& clock_port, + const float& delay); + #endif 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 8fa4709f1..edff64348 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 @@ -160,6 +160,7 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, fpga_sdc_generator(sdc_options, Arch.spice->spice_params.stimulate_params.vpr_crit_path_delay / 1e-9, grids, rr_switches, device_rr_gsb, + L_logical_blocks, device_size, grids, L_blocks, module_manager, mux_lib, Arch.spice->circuit_lib, global_ports, TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy); From 67b3b25bea66f3e971060e487e3b0128f3fb9c78 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 10 Nov 2019 16:08:49 -0700 Subject: [PATCH 56/68] refactoring analysis sdc generation --- .../backend_assistant/analysis_sdc_writer.cpp | 64 +++++++++++++------ .../backend_assistant/pnr_sdc_writer.cpp | 55 +--------------- .../backend_assistant/sdc_memory_utils.cpp | 62 ++++++++++++++++++ .../backend_assistant/sdc_memory_utils.h | 13 ++++ 4 files changed, 120 insertions(+), 74 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_memory_utils.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_memory_utils.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp index 4a5fe91c3..a85a2ae3d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp @@ -18,6 +18,7 @@ #include "sdc_writer_naming.h" #include "sdc_writer_utils.h" +#include "sdc_memory_utils.h" #include "analysis_sdc_writer.h" @@ -56,8 +57,9 @@ void print_analysis_sdc_io_delays(std::fstream& fp, continue; } - /* Update the operating port list */ - operating_clock_ports.push_back(BasicPort(circuit_lib.port_prefix(clock_port), circuit_lib.port_size(clock_port))); + /* Find the module port and Update the operating port list */ + ModulePortId module_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(clock_port)); + operating_clock_ports.push_back(module_manager.module_port(top_module, module_port)); } for (const BasicPort& operating_clock_port : operating_clock_ports) { @@ -151,6 +153,37 @@ void print_analysis_sdc_io_delays(std::fstream& fp, fp << std::endl; } +/******************************************************************** + * Disable the timing for all the global port except the operating clock ports + *******************************************************************/ +static +void print_analysis_sdc_disable_global_ports(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const std::vector& global_ports) { + /* Validate file stream */ + check_file_handler(fp); + + /* Print comments */ + fp << "##################################################" << std::endl; + fp << "# Disable timing for global ports " << std::endl; + fp << "##################################################" << std::endl; + + for (const CircuitPortId& global_port : global_ports) { + /* Skip operating clock here! */ + if ( (SPICE_MODEL_PORT_CLOCK == circuit_lib.port_type(global_port)) + && (false == circuit_lib.port_is_prog(global_port)) ) { + continue; + } + + ModulePortId module_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(global_port)); + BasicPort port_to_disable = module_manager.module_port(top_module, module_port); + + print_sdc_disable_port_timing(fp, port_to_disable); + } +} + /******************************************************************** * Top-level function outputs a SDC file * that constrain a FPGA fabric (P&Red netlist) using a benchmark @@ -197,27 +230,18 @@ void print_analysis_sdc(const std::string& sdc_dir, circuit_lib, global_ports, critical_path_delay); - /* TODO: Disable the timing for global ports */ - /* - verilog_generate_sdc_disable_global_ports(fp); - */ + /* Disable the timing for global ports */ + print_analysis_sdc_disable_global_ports(fp, + module_manager, top_module, + circuit_lib, global_ports); + + /* Disable the timing for configuration cells */ + rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, + module_manager, top_module, + format_dir_path(module_manager.module_name(top_module))); - /* TODO: Disable the timing for configuration cells */ - /* - verilog_generate_sdc_disable_sram_orgz(fp, cur_sram_orgz_info); - */ /* TODO: Disable timing for un-used resources */ - /* Apply to Routing Channels */ - /* - if (TRUE == compact_routing_hierarchy) { - verilog_generate_sdc_disable_unused_routing_channels(fp, LL_nx, LL_ny); - } else { - verilog_generate_sdc_disable_unused_routing_channels(fp, LL_nx, LL_ny, - LL_num_rr_nodes, LL_rr_node, - LL_rr_node_indices); - } - */ /* TODO: Apply to Connection blocks */ /* diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp index b5f58bf90..771e4ba22 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_writer.cpp @@ -23,6 +23,7 @@ #include "sdc_writer_naming.h" #include "sdc_writer_utils.h" +#include "sdc_memory_utils.h" #include "pnr_sdc_routing_writer.h" #include "pnr_sdc_grid_writer.h" #include "pnr_sdc_writer.h" @@ -142,60 +143,6 @@ void print_pnr_sdc_global_ports(const std::string& sdc_dir, run_time_sec); } -/******************************************************************** - * Print SDC commands to disable outputs of all the configurable memory modules - * in a given module - * This function will be executed in a recursive way, - * using a Depth-First Search (DFS) strategy - * It will iterate over all the configurable children under each module - * and print a SDC command to disable its outputs - *******************************************************************/ -static -void rec_print_pnr_sdc_disable_configurable_memory_module_output(std::fstream& fp, - const ModuleManager& module_manager, - const ModuleId& parent_module, - const std::string& parent_module_path) { - - /* For each configurable child, we will go one level down in priority */ - for (size_t child_index = 0; child_index < module_manager.configurable_children(parent_module).size(); ++child_index) { - std::string child_module_path = parent_module_path; - ModuleId child_module_id = module_manager.configurable_children(parent_module)[child_index]; - size_t child_instance_id = module_manager.configurable_child_instances(parent_module)[child_index]; - if (true == module_manager.instance_name(parent_module, child_module_id, child_instance_id).empty()) { - /* Give a default name __ */ - child_module_path += module_manager.module_name(child_module_id); - child_module_path += "_"; - child_module_path += std::to_string(child_instance_id); - child_module_path += "_"; - } else { - child_module_path += module_manager.instance_name(parent_module, child_module_id, child_instance_id); - } - child_module_path = format_dir_path(child_module_path); - - rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, module_manager, - child_module_id, - child_module_path); - } - - /* If there is no configurable children any more, this is a leaf module, print a SDC command for disable timing */ - if (0 < module_manager.configurable_children(parent_module).size()) { - return; - } - - /* Validate file stream */ - check_file_handler(fp); - - /* Disable timing for each output port of this module */ - for (const BasicPort& output_port : module_manager.module_ports_by_type(parent_module, ModuleManager::MODULE_OUTPUT_PORT)) { - for (const size_t& pin : output_port.pins()) { - BasicPort output_pin(output_port.get_name(), pin, pin); - fp << "set_disable_timing "; - fp << parent_module_path << generate_sdc_port(output_pin); - fp << std::endl; - } - } -} - /******************************************************************** * Break combinational loops in FPGA fabric, which mainly come from * configurable memory cells. diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_memory_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_memory_utils.cpp new file mode 100644 index 000000000..6df5ede5f --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_memory_utils.cpp @@ -0,0 +1,62 @@ +/******************************************************************** + * Most utilized function used to constrain memory cells in FPGA + * fabric using SDC commands + *******************************************************************/ +#include "fpga_x2p_utils.h" +#include "sdc_writer_utils.h" + +#include "sdc_memory_utils.h" + +/******************************************************************** + * Print SDC commands to disable outputs of all the configurable memory modules + * in a given module + * This function will be executed in a recursive way, + * using a Depth-First Search (DFS) strategy + * It will iterate over all the configurable children under each module + * and print a SDC command to disable its outputs + *******************************************************************/ +void rec_print_pnr_sdc_disable_configurable_memory_module_output(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& parent_module_path) { + + /* For each configurable child, we will go one level down in priority */ + for (size_t child_index = 0; child_index < module_manager.configurable_children(parent_module).size(); ++child_index) { + std::string child_module_path = parent_module_path; + ModuleId child_module_id = module_manager.configurable_children(parent_module)[child_index]; + size_t child_instance_id = module_manager.configurable_child_instances(parent_module)[child_index]; + if (true == module_manager.instance_name(parent_module, child_module_id, child_instance_id).empty()) { + /* Give a default name __ */ + child_module_path += module_manager.module_name(child_module_id); + child_module_path += "_"; + child_module_path += std::to_string(child_instance_id); + child_module_path += "_"; + } else { + child_module_path += module_manager.instance_name(parent_module, child_module_id, child_instance_id); + } + child_module_path = format_dir_path(child_module_path); + + rec_print_pnr_sdc_disable_configurable_memory_module_output(fp, module_manager, + child_module_id, + child_module_path); + } + + /* If there is no configurable children any more, this is a leaf module, print a SDC command for disable timing */ + if (0 < module_manager.configurable_children(parent_module).size()) { + return; + } + + /* Validate file stream */ + check_file_handler(fp); + + /* Disable timing for each output port of this module */ + for (const BasicPort& output_port : module_manager.module_ports_by_type(parent_module, ModuleManager::MODULE_OUTPUT_PORT)) { + for (const size_t& pin : output_port.pins()) { + BasicPort output_pin(output_port.get_name(), pin, pin); + fp << "set_disable_timing "; + fp << parent_module_path << generate_sdc_port(output_pin); + fp << std::endl; + } + } +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_memory_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_memory_utils.h new file mode 100644 index 000000000..9ce57d6d8 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_memory_utils.h @@ -0,0 +1,13 @@ +#ifndef SDC_MEMORY_UTILS_H +#define SDC_MEMORY_UTILS_H + +#include +#include +#include "module_manager.h" + +void rec_print_pnr_sdc_disable_configurable_memory_module_output(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& parent_module_path); + +#endif From 3d711823e53f9c31abd78834badbad82b09ee76c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 10 Nov 2019 18:15:13 -0700 Subject: [PATCH 57/68] refactoring SDC generator for unused CBs --- .../analysis_sdc_routing_writer.cpp | 240 ++++++++++++++++++ .../analysis_sdc_routing_writer.h | 15 ++ .../backend_assistant/analysis_sdc_writer.cpp | 21 +- .../fpga_x2p/backend_assistant/sdc_api.cpp | 2 +- 4 files changed, 263 insertions(+), 15 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp new file mode 100644 index 000000000..93cf918ce --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp @@ -0,0 +1,240 @@ +/******************************************************************** + * This file includes functions that are used to output a SDC file + * that constrain routing modules of a FPGA fabric (P&Red netlist) + * using a benchmark + *******************************************************************/ +#include "vtr_assert.h" +#include "device_port.h" + +#include "fpga_x2p_naming.h" +#include "fpga_x2p_utils.h" + + +#include "sdc_writer_utils.h" +#include "analysis_sdc_routing_writer.h" + +#include "globals.h" + +/******************************************************************** + * Identify if a node should be disabled during analysis SDC generation + *******************************************************************/ +static +bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node) { + /* Conditions to enable timing analysis for a node + * 1st condition: it have a valid vpack_net_number + * 2nd condition: it is not an parasitic net + * 3rd condition: it is not a global net + */ + if ( (OPEN != cur_rr_node->vpack_net_num) + && (FALSE == cur_rr_node->is_parasitic_net) + && (FALSE == vpack_net[cur_rr_node->vpack_net_num].is_global) + && (FALSE == vpack_net[cur_rr_node->vpack_net_num].is_const_gen) ){ + return false; + } + return true; +} + +/******************************************************************** + * This function will disable + * 1. all the unused port (unmapped by a benchmark) of a connection block + * 2. all the unused inputs (unmapped by a benchmark) of routing multiplexers + * in a connection block + *******************************************************************/ +static +void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, + const std::vector>& grids, + const DeviceRRGSB& L_device_rr_gsb, + const ModuleManager& module_manager, + const RRGSB& rr_gsb, + const t_rr_type& cb_type, + const bool& compact_routing_hierarchy) { + /* Validate file stream */ + check_file_handler(fp); + + vtr::Point gsb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); + + std::string cb_instance_name = generate_connection_block_module_name(cb_type, gsb_coordinate); + + /* If we use the compact routing hierarchy, we need to find the module name !*/ + vtr::Point cb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); + if (true == compact_routing_hierarchy) { + DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + /* Note: use GSB coordinate when inquire for unique modules!!! */ + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord); + cb_coordinate.set_x(unique_mirror.get_cb_x(cb_type)); + cb_coordinate.set_y(unique_mirror.get_cb_y(cb_type)); + } + + std::string cb_module_name = generate_connection_block_module_name(cb_type, cb_coordinate); + + ModuleId cb_module = module_manager.find_module(cb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(cb_module)); + + /* Print comments */ + fp << "##################################################" << std::endl; + fp << "# Disable timing for Connection block " << cb_module_name << std::endl; + fp << "##################################################" << std::endl; + + /* Disable all the input port (routing tracks), which are not used by benchmark */ + for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) { + t_rr_node* chan_node = rr_gsb.get_chan_node(rr_gsb.get_cb_chan_side(cb_type), itrack); + /* Check if this node is used by benchmark */ + if (false == is_rr_node_to_be_disable_for_analysis(chan_node)) { + continue; + } + + /* Disable both input of the routing track if it is not used! */ + vtr::Point port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); + if (true == compact_routing_hierarchy) { + /* Note: use GSB coordinate when inquire for unique modules!!! */ + DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord); + port_coord.set_x(unique_mirror.get_cb_x(cb_type)); + port_coord.set_y(unique_mirror.get_cb_y(cb_type)); + } + std::string port_name = generate_routing_track_port_name(cb_type, + port_coord, itrack, + IN_PORT); + + /* Ensure we have this port in the module! */ + ModulePortId module_port = module_manager.find_module_port(cb_module, port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port)); + + fp << "set_disable_timing "; + fp << cb_instance_name << "/"; + fp << generate_sdc_port(module_manager.module_port(cb_module, module_port)); + fp << std::endl; + } + + /* Disable all the output port (routing tracks), which are not used by benchmark */ + for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) { + t_rr_node* chan_node = rr_gsb.get_chan_node(rr_gsb.get_cb_chan_side(cb_type), itrack); + /* Check if this node is used by benchmark */ + if (false == is_rr_node_to_be_disable_for_analysis(chan_node)) { + continue; + } + + /* Disable both input of the routing track if it is not used! */ + vtr::Point port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); + if (true == compact_routing_hierarchy) { + /* Note: use GSB coordinate when inquire for unique modules!!! */ + DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord); + port_coord.set_x(unique_mirror.get_cb_x(cb_type)); + port_coord.set_y(unique_mirror.get_cb_y(cb_type)); + } + std::string port_name = generate_routing_track_port_name(cb_type, + port_coord, itrack, + OUT_PORT); + + /* Ensure we have this port in the module! */ + ModulePortId module_port = module_manager.find_module_port(cb_module, port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port)); + + fp << "set_disable_timing "; + fp << cb_instance_name << "/"; + fp << generate_sdc_port(module_manager.module_port(cb_module, module_port)); + fp << std::endl; + } + + /* Disable all the output port (grid input pins), which are not used by benchmark */ + std::vector cb_sides = rr_gsb.get_cb_ipin_sides(cb_type); + + for (size_t side = 0; side < cb_sides.size(); ++side) { + enum e_side cb_ipin_side = cb_sides[side]; + for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) { + t_rr_node* ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode); + if (false == is_rr_node_to_be_disable_for_analysis(ipin_node)) { + continue; + } + if (0 == ipin_node->fan_in) { + continue; + } + vtr::Point port_coord(ipin_node->xlow, ipin_node->ylow); + std::string port_name = generate_grid_side_port_name(grids, + port_coord, + rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), + ipin_node->ptc_num); + + /* Find the port in unique mirror! */ + if (true == compact_routing_hierarchy) { + /* Note: use GSB coordinate when inquire for unique modules!!! */ + DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord); + t_rr_node* unique_mirror_ipin_node = unique_mirror.get_ipin_node(cb_ipin_side, inode); + port_coord.set_x(unique_mirror_ipin_node->xlow); + port_coord.set_y(unique_mirror_ipin_node->ylow); + port_name = generate_grid_side_port_name(grids, + port_coord, + unique_mirror.get_ipin_node_grid_side(cb_ipin_side, inode), + unique_mirror_ipin_node->ptc_num); + } + + /* Ensure we have this port in the module! */ + ModulePortId module_port = module_manager.find_module_port(cb_module, port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port)); + + fp << "set_disable_timing "; + fp << cb_instance_name << "/"; + fp << generate_sdc_port(module_manager.module_port(cb_module, module_port)); + fp << std::endl; + } + } + + /* TODO: Disable all the unused inputs of routing multiplexers, which are not used by benchmark */ +} + + +/******************************************************************** + * Iterate over all the connection blocks in a device + * and disable unused ports for each of them + *******************************************************************/ +static +void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp, + const std::vector>& grids, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const t_rr_type& cb_type, + const bool& compact_routing_hierarchy) { + /* Build unique X-direction connection block modules */ + DeviceCoordinator cb_range = L_device_rr_gsb.get_gsb_range(); + + for (size_t ix = 0; ix < cb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < cb_range.get_y(); ++iy) { + /* Check if the connection block exists in the device! + * Some of them do NOT exist due to heterogeneous blocks (height > 1) + * We will skip those modules + */ + const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); + if (false == rr_gsb.is_cb_exist(cb_type)) { + continue; + } + + print_analysis_sdc_disable_cb_unused_resources(fp, grids, L_device_rr_gsb, + module_manager, + rr_gsb, + cb_type, + compact_routing_hierarchy); + } + } +} + +/******************************************************************** + * Iterate over all the connection blocks in a device + * and disable unused ports for each of them + *******************************************************************/ +void print_analysis_sdc_disable_unused_cbs(std::fstream& fp, + const std::vector>& grids, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const bool& compact_routing_hierarchy) { + + print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager, + L_device_rr_gsb, + CHANX, compact_routing_hierarchy); + + print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager, + L_device_rr_gsb, + CHANY, compact_routing_hierarchy); +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h new file mode 100644 index 000000000..21154b1d8 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h @@ -0,0 +1,15 @@ +#ifndef ANALYSIS_SDC_ROUTING_WRITER_H +#define ANALYSIS_SDC_ROUTING_WRITER_H + +#include +#include +#include "module_manager.h" +#include "rr_blocks.h" +#include "vpr_types.h" + +void print_analysis_sdc_disable_unused_cbs(std::fstream& fp, + const std::vector>& grids, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const bool& compact_routing_hierarchy); +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp index a85a2ae3d..351d3a74a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp @@ -20,6 +20,7 @@ #include "sdc_writer_utils.h" #include "sdc_memory_utils.h" +#include "analysis_sdc_routing_writer.h" #include "analysis_sdc_writer.h" /******************************************************************** @@ -241,20 +242,12 @@ void print_analysis_sdc(const std::string& sdc_dir, format_dir_path(module_manager.module_name(top_module))); - /* TODO: Disable timing for un-used resources */ + /* TODO: Disable timing for unused routing resources in connection blocks */ + print_analysis_sdc_disable_unused_cbs(fp, L_grids, module_manager, + L_device_rr_gsb, + compact_routing_hierarchy); - /* TODO: Apply to Connection blocks */ - /* - if (TRUE == compact_routing_hierarchy) { - verilog_generate_sdc_disable_unused_cbs(fp, LL_nx, LL_ny, LL_device_rr_gsb); - verilog_generate_sdc_disable_unused_cbs_muxs(fp, LL_nx, LL_ny, LL_device_rr_gsb); - } else { - verilog_generate_sdc_disable_unused_cbs(fp, LL_nx, LL_ny); - verilog_generate_sdc_disable_unused_cbs_muxs(fp, LL_nx, LL_ny); - } - */ - - /* TODO: Apply to Switch blocks */ + /* TODO: Disable timing for unused routing resources in switch blocks */ /* if (TRUE == compact_routing_hierarchy) { verilog_generate_sdc_disable_unused_sbs(fp); @@ -265,7 +258,7 @@ void print_analysis_sdc(const std::string& sdc_dir, } */ - /* TODO: Apply to Grids */ + /* TODO: Disable timing for unused routing resources in grids (programmable blocks) */ /* verilog_generate_sdc_disable_unused_grids(fp, LL_nx, LL_ny, LL_grid, LL_block); verilog_generate_sdc_disable_unused_grids_muxs(fp, LL_nx, LL_ny, LL_grid, LL_block); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp index bf9f17858..a8c76c6d6 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp @@ -25,7 +25,7 @@ void fpga_sdc_generator(const SdcOption& sdc_options, const std::vector& global_ports, const bool& compact_routing_hierarchy) { vpr_printf(TIO_MESSAGE_INFO, - "SDC generator starts..."); + "SDC generator starts...\n"); /* Start time count */ clock_t t_start = clock(); From 8e8e59b0ca367c803547677954fe33ca798d9145 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 10 Nov 2019 19:42:30 -0700 Subject: [PATCH 58/68] give specific name to mux so that we can bind it to SDC generator --- .../vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp | 71 +++++++++++++++++++ .../vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h | 14 ++++ .../fpga_x2p/base/fpga_x2p_reserved_words.h | 4 ++ .../module_builder/build_grid_modules.cpp | 5 ++ .../module_builder/build_routing_modules.cpp | 12 ++++ 5 files changed, 106 insertions(+) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp index a90a301e2..72bc59994 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp @@ -758,6 +758,25 @@ std::string generate_grid_block_module_name(const std::string& prefix, return module_name; } +/********************************************************************* + * Generate the instance name for a programmable routing multiplexer module + * in a Switch Block + * To keep a unique name in each module and also consider unique routing modules, + * please do NOT include any coordinates in the naming!!! + * Consider only relative coordinate, such as side! + ********************************************************************/ +std::string generate_sb_mux_instance_name(const std::string& prefix, + const e_side& sb_side, + const size_t& track_id, + const std::string& postfix) { + std::string instance_name(prefix); + instance_name += Side(sb_side).to_string(); + instance_name += std::string("_track_") + std::to_string(track_id); + instance_name += postfix; + + return instance_name; +} + /********************************************************************* * Generate the instance name for a configurable memory module in a Switch Block * To keep a unique name in each module and also consider unique routing modules, @@ -776,6 +795,26 @@ std::string generate_sb_memory_instance_name(const std::string& prefix, return instance_name; } +/********************************************************************* + * Generate the instance name for a programmable routing multiplexer module + * in a Connection Block + * To keep a unique name in each module and also consider unique routing modules, + * please do NOT include any coordinates in the naming!!! + * Consider only relative coordinate, such as side! + ********************************************************************/ +std::string generate_cb_mux_instance_name(const std::string& prefix, + const e_side& cb_side, + const size_t& pin_id, + const std::string& postfix) { + std::string instance_name(prefix); + + instance_name += Side(cb_side).to_string(); + instance_name += std::string("_ipin_") + std::to_string(pin_id); + instance_name += postfix; + + return instance_name; +} + /********************************************************************* * Generate the instance name for a configurable memory module in a Connection Block * To keep a unique name in each module and also consider unique routing modules, @@ -795,6 +834,38 @@ std::string generate_cb_memory_instance_name(const std::string& prefix, return instance_name; } +/********************************************************************* + * Generate the instance name for a programmable routing multiplexer + * module in a physical block of a grid + * To guarentee a unique name for pb_graph pin, + * the instance name includes the index of parent node + * as well as the port name and pin index of this pin + * + * Exceptions: + * For OUTPUT ports, due to hierarchical module organization, + * their parent nodes will be uniquified + * So, we should not add any index here + ********************************************************************/ +std::string generate_pb_mux_instance_name(const std::string& prefix, + t_pb_graph_pin* pb_graph_pin, + const std::string& postfix) { + std::string instance_name(prefix); + instance_name += std::string(pb_graph_pin->parent_node->pb_type->name); + + if (IN_PORT == pb_graph_pin->port->type) { + instance_name += std::string("_"); + instance_name += std::to_string(pb_graph_pin->parent_node->placement_index); + } + + instance_name += std::string("_"); + instance_name += std::string(pb_graph_pin->port->name); + instance_name += std::string("_"); + instance_name += std::to_string(pb_graph_pin->pin_number); + instance_name += postfix; + + return instance_name; +} + /********************************************************************* * Generate the instance name for a configurable memory module in a * physical block of a grid 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 56f3c627d..83e84af3b 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 @@ -78,16 +78,30 @@ std::string generate_switch_block_module_name(const vtr::Point& coordina std::string generate_connection_block_module_name(const t_rr_type& cb_type, const vtr::Point& coordinate); +std::string generate_sb_mux_instance_name(const std::string& prefix, + const e_side& sb_side, + const size_t& track_id, + const std::string& postfix); + std::string generate_sb_memory_instance_name(const std::string& prefix, const e_side& sb_side, const size_t& track_id, const std::string& postfix); +std::string generate_cb_mux_instance_name(const std::string& prefix, + const e_side& cb_side, + const size_t& pin_id, + const std::string& postfix); + std::string generate_cb_memory_instance_name(const std::string& prefix, const e_side& cb_side, const size_t& pin_id, const std::string& postfix); +std::string generate_pb_mux_instance_name(const std::string& prefix, + t_pb_graph_pin* pb_graph_pin, + const std::string& postfix); + std::string generate_pb_memory_instance_name(const std::string& prefix, t_pb_graph_pin* pb_graph_pin, const std::string& postfix); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_reserved_words.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_reserved_words.h index face6ad8f..c334feef1 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_reserved_words.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_reserved_words.h @@ -16,6 +16,10 @@ constexpr char* SWITCH_BLOCK_MEM_INSTANCE_PREFIX = "mem_"; constexpr char* CONNECTION_BLOCK_MEM_INSTANCE_PREFIX = "mem_"; constexpr char* MEMORY_MODULE_POSTFIX = "_mem"; +/* Multiplexer naming constant strings */ +constexpr char* GRID_MUX_INSTANCE_PREFIX = "mux_"; +constexpr char* SWITCH_BLOCK_MUX_INSTANCE_PREFIX = "mux_"; +constexpr char* CONNECTION_BLOCK_MUX_INSTANCE_PREFIX = "mux_"; /* Bitstream file strings */ constexpr char* BITSTREAM_XML_FILE_NAME_POSTFIX = "_bitstream.xml"; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp index b298c22c1..e23ec60f9 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp @@ -559,6 +559,11 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager, /* Instanciate the MUX */ size_t mux_instance = module_manager.num_instance(pb_module, mux_module); module_manager.add_child_module(pb_module, mux_module); + /* Give an instance name: this name should be consistent with the block name given in SDC generator, + * If you want to bind the SDC generation to modules + */ + std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, des_pb_graph_pin, std::string("")); + module_manager.set_child_instance_name(pb_module, mux_module, mux_instance, mux_instance_name); /* Instanciate a memory module for the MUX */ std::string mux_mem_module_name = generate_mux_subckt_name(circuit_lib, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp index d2b5b4464..b43baa0f4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp @@ -128,6 +128,12 @@ void build_switch_block_mux_module(ModuleManager& module_manager, /* Instanciate the MUX Module */ module_manager.add_child_module(sb_module, mux_module); + /* Give an instance name: this name should be consistent with the block name given in SDC manager, + * If you want to bind the SDC generation to modules + */ + std::string mux_instance_name = generate_sb_memory_instance_name(SWITCH_BLOCK_MUX_INSTANCE_PREFIX, chan_side, chan_node_id, std::string("")); + module_manager.set_child_instance_name(sb_module, mux_module, mux_instance_id, mux_instance_name); + /* Generate input ports that are wired to the input bus of the routing multiplexer */ std::vector sb_input_port_ids = find_switch_block_module_input_ports(module_manager, sb_module, rr_gsb, grids, drive_rr_nodes); @@ -515,6 +521,12 @@ void build_connection_block_mux_module(ModuleManager& module_manager, size_t mux_instance_id = module_manager.num_instance(cb_module, mux_module); module_manager.add_child_module(cb_module, mux_module); + /* Give an instance name: this name should be consistent with the block name given in SDC manager, + * If you want to bind the SDC generation to modules + */ + std::string mux_instance_name = generate_cb_mux_instance_name(CONNECTION_BLOCK_MUX_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, ipin_index), ipin_index, std::string("")); + module_manager.set_child_instance_name(cb_module, mux_module, mux_instance_id, mux_instance_name); + /* TODO: Generate input ports that are wired to the input bus of the routing multiplexer */ std::vector cb_input_port_ids = find_connection_block_module_input_ports(module_manager, cb_module, rr_gsb, cb_type, drive_rr_nodes); From a849522be9d4111bf32fe5785f729e548ecfb578 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 10 Nov 2019 20:15:16 -0700 Subject: [PATCH 59/68] refactored CB SDC analysis generation --- .../analysis_sdc_routing_writer.cpp | 115 ++++++++++++++++-- .../analysis_sdc_routing_writer.h | 3 + .../backend_assistant/analysis_sdc_writer.cpp | 6 +- .../backend_assistant/analysis_sdc_writer.h | 2 + .../fpga_x2p/backend_assistant/sdc_api.cpp | 8 +- .../SRC/fpga_x2p/backend_assistant/sdc_api.h | 3 +- vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c | 2 +- 7 files changed, 126 insertions(+), 13 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp index 93cf918ce..d092dc3cf 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp @@ -6,9 +6,10 @@ #include "vtr_assert.h" #include "device_port.h" +#include "fpga_x2p_reserved_words.h" #include "fpga_x2p_naming.h" #include "fpga_x2p_utils.h" - +#include "fpga_x2p_types.h" #include "sdc_writer_utils.h" #include "analysis_sdc_routing_writer.h" @@ -43,8 +44,11 @@ bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node) { static void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, const std::vector>& grids, - const DeviceRRGSB& L_device_rr_gsb, + const std::vector& rr_switches, + t_rr_node* L_rr_node, const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const CircuitLibrary& circuit_lib, const RRGSB& rr_gsb, const t_rr_type& cb_type, const bool& compact_routing_hierarchy) { @@ -182,6 +186,96 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, } /* TODO: Disable all the unused inputs of routing multiplexers, which are not used by benchmark */ + for (size_t side = 0; side < cb_sides.size(); ++side) { + enum e_side cb_ipin_side = cb_sides[side]; + for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) { + t_rr_node* ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode); + if (false == is_rr_node_to_be_disable_for_analysis(ipin_node)) { + continue; + } + if (0 == ipin_node->fan_in) { + continue; + } + vtr::Point port_coord(ipin_node->xlow, ipin_node->ylow); + std::string port_name = generate_grid_side_port_name(grids, + port_coord, + rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), + ipin_node->ptc_num); + + /* Find the port in unique mirror! */ + if (true == compact_routing_hierarchy) { + /* Note: use GSB coordinate when inquire for unique modules!!! */ + DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord); + t_rr_node* unique_mirror_ipin_node = unique_mirror.get_ipin_node(cb_ipin_side, inode); + port_coord.set_x(unique_mirror_ipin_node->xlow); + port_coord.set_y(unique_mirror_ipin_node->ylow); + port_name = generate_grid_side_port_name(grids, + port_coord, + unique_mirror.get_ipin_node_grid_side(cb_ipin_side, inode), + unique_mirror_ipin_node->ptc_num); + } + + /* These codes are exactly same in build_routing_modules.cpp + * If you wish to change the naming rules, please change build_routing_modules.cpp as well + * so that consistency remains + */ + /* Build a vector of driver rr_nodes */ + std::vector drive_rr_nodes; + for (int jnode = 0; jnode < ipin_node->num_drive_rr_nodes; jnode++) { + drive_rr_nodes.push_back(ipin_node->drive_rr_nodes[jnode]); + } + + int switch_index = ipin_node->drive_switches[DEFAULT_SWITCH_ID]; + + /* Get the circuit model id of the routing multiplexer */ + CircuitModelId mux_model = rr_switches[switch_index].circuit_model; + + /* Find the input size of the implementation of a routing multiplexer */ + size_t datapath_mux_size = drive_rr_nodes.size(); + + /* Find the module name of the multiplexer and try to find it in the module manager */ + std::string mux_module_name = generate_mux_subckt_name(circuit_lib, mux_model, datapath_mux_size, std::string("")); + ModuleId mux_module = module_manager.find_module(mux_module_name); + VTR_ASSERT (true == module_manager.valid_module_id(mux_module)); + + /* Find the MUX instance that drives the IPIN! */ + std::string mux_instance_name = generate_cb_mux_instance_name(CONNECTION_BLOCK_MUX_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), inode, std::string("")); + + /* Make sure this instance name exists! */ + size_t instance_id = module_manager.instance_id(cb_module, mux_module, mux_instance_name); + VTR_ASSERT(instance_id < module_manager.num_instance(cb_module, mux_module)); + + /* Find the MUX input port from model to module */ + std::vector mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true); + VTR_ASSERT(1 == mux_model_input_ports.size()); + /* Find the module port id of the input port */ + ModulePortId mux_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_input_ports[0])); + VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_input_port_id)); + BasicPort mux_input_port = module_manager.module_port(mux_module, mux_input_port_id); + + /* Find out which routing path is used in this MUX */ + int path_id = DEFAULT_PATH_ID; + for (size_t jnode = 0; jnode < drive_rr_nodes.size(); ++jnode) { + if (drive_rr_nodes[jnode] == &(L_rr_node[ipin_node->prev_node])) { + path_id = (int)jnode; + break; + } + } + + for (const size_t& pin : mux_input_port.pins()) { + if ((size_t)path_id == pin) { + continue; /* For used pin, skip disable timing */ + } + /* Get the input id that is used! Disable the unused inputs! */ + fp << "set_disable_timing "; + fp << cb_instance_name << "/"; + fp << mux_instance_name << "/"; + fp << generate_sdc_port(BasicPort(mux_input_port.get_name(), pin, pin)); + fp << std::endl; + } + } + } } @@ -192,7 +286,10 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, static void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp, const std::vector>& grids, + const std::vector& rr_switches, + t_rr_node* L_rr_node, const ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, const DeviceRRGSB& L_device_rr_gsb, const t_rr_type& cb_type, const bool& compact_routing_hierarchy) { @@ -210,8 +307,9 @@ void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp, continue; } - print_analysis_sdc_disable_cb_unused_resources(fp, grids, L_device_rr_gsb, + print_analysis_sdc_disable_cb_unused_resources(fp, grids, rr_switches, L_rr_node, module_manager, + L_device_rr_gsb, circuit_lib, rr_gsb, cb_type, compact_routing_hierarchy); @@ -225,16 +323,19 @@ void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp, *******************************************************************/ void print_analysis_sdc_disable_unused_cbs(std::fstream& fp, const std::vector>& grids, + const std::vector& rr_switches, + t_rr_node* L_rr_node, const ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, const DeviceRRGSB& L_device_rr_gsb, const bool& compact_routing_hierarchy) { - print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager, - L_device_rr_gsb, + print_analysis_sdc_disable_unused_cb_ports(fp, grids, rr_switches, L_rr_node, module_manager, + circuit_lib, L_device_rr_gsb, CHANX, compact_routing_hierarchy); - print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager, - L_device_rr_gsb, + print_analysis_sdc_disable_unused_cb_ports(fp, grids, rr_switches, L_rr_node, module_manager, + circuit_lib, L_device_rr_gsb, CHANY, compact_routing_hierarchy); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h index 21154b1d8..d05fcf226 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h @@ -9,7 +9,10 @@ void print_analysis_sdc_disable_unused_cbs(std::fstream& fp, const std::vector>& grids, + const std::vector& rr_switches, + t_rr_node* L_rr_node, const ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, const DeviceRRGSB& L_device_rr_gsb, const bool& compact_routing_hierarchy); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp index 351d3a74a..1ee475e16 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp @@ -195,6 +195,8 @@ void print_analysis_sdc(const std::string& sdc_dir, const std::vector& L_logical_blocks, const vtr::Point& device_size, const std::vector>& L_grids, + const std::vector& rr_switches, + t_rr_node* L_rr_node, const std::vector& L_blocks, const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, @@ -243,7 +245,9 @@ void print_analysis_sdc(const std::string& sdc_dir, /* TODO: Disable timing for unused routing resources in connection blocks */ - print_analysis_sdc_disable_unused_cbs(fp, L_grids, module_manager, + print_analysis_sdc_disable_unused_cbs(fp, L_grids, rr_switches, L_rr_node, + module_manager, + circuit_lib, L_device_rr_gsb, compact_routing_hierarchy); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h index 252c76c71..aeb55247d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h @@ -13,6 +13,8 @@ void print_analysis_sdc(const std::string& sdc_dir, const std::vector& L_logical_blocks, const vtr::Point& device_size, const std::vector>& L_grids, + const std::vector& rr_switches, + t_rr_node* L_rr_node, const std::vector& L_blocks, const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp index a8c76c6d6..e3666051a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp @@ -13,7 +13,8 @@ void fpga_sdc_generator(const SdcOption& sdc_options, const float& critical_path_delay, const std::vector>& grids, - const std::vector& switches, + const std::vector& rr_switches, + t_rr_node* L_rr_node, const DeviceRRGSB& L_device_rr_gsb, const std::vector& L_logical_blocks, const vtr::Point& device_size, @@ -32,7 +33,7 @@ void fpga_sdc_generator(const SdcOption& sdc_options, if (true == sdc_options.generate_sdc_pnr()) { print_pnr_sdc(sdc_options, critical_path_delay, - grids, switches, L_device_rr_gsb, + grids, rr_switches, L_device_rr_gsb, module_manager, mux_lib, circuit_lib, global_ports, compact_routing_hierarchy); @@ -42,7 +43,8 @@ void fpga_sdc_generator(const SdcOption& sdc_options, print_analysis_sdc(sdc_options.sdc_dir(), critical_path_delay, L_device_rr_gsb, - L_logical_blocks, device_size, L_grids, L_blocks, + L_logical_blocks, device_size, L_grids, rr_switches, L_rr_node, + L_blocks, module_manager, circuit_lib, global_ports, compact_routing_hierarchy); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h index 02874e3a3..51f0beb64 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h @@ -10,7 +10,8 @@ void fpga_sdc_generator(const SdcOption& sdc_options, const float& critical_path_delay, const std::vector>& grids, - const std::vector& switches, + const std::vector& rr_switches, + t_rr_node* L_rr_node, const DeviceRRGSB& L_device_rr_gsb, const std::vector& L_logical_blocks, const vtr::Point& device_size, 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 edff64348..0a2ba84cf 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 @@ -159,7 +159,7 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, /* 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, - grids, rr_switches, device_rr_gsb, + grids, rr_switches, rr_node, device_rr_gsb, L_logical_blocks, device_size, grids, L_blocks, module_manager, mux_lib, Arch.spice->circuit_lib, global_ports, From 876733f052ddaeb1c056e458be3b54832e48b246 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 10 Nov 2019 21:15:34 -0700 Subject: [PATCH 60/68] now we use module manager to generate analysis SDC, being independent from VPR structures --- .../analysis_sdc_routing_writer.cpp | 177 +++++++++--------- .../analysis_sdc_routing_writer.h | 3 - .../backend_assistant/analysis_sdc_writer.cpp | 5 +- .../backend_assistant/analysis_sdc_writer.h | 2 - .../fpga_x2p/backend_assistant/sdc_api.cpp | 3 +- .../SRC/fpga_x2p/backend_assistant/sdc_api.h | 1 - vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_api.c | 2 +- 7 files changed, 88 insertions(+), 105 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp index d092dc3cf..48a798aab 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp @@ -3,6 +3,8 @@ * that constrain routing modules of a FPGA fabric (P&Red netlist) * using a benchmark *******************************************************************/ +#include + #include "vtr_assert.h" #include "device_port.h" @@ -44,11 +46,8 @@ bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node) { static void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, const std::vector>& grids, - const std::vector& rr_switches, - t_rr_node* L_rr_node, const ModuleManager& module_manager, const DeviceRRGSB& L_device_rr_gsb, - const CircuitLibrary& circuit_lib, const RRGSB& rr_gsb, const t_rr_type& cb_type, const bool& compact_routing_hierarchy) { @@ -141,6 +140,9 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, fp << std::endl; } + /* Build a map between mux_instance name and net_num */ + std::map mux_instance_to_net_map; + /* Disable all the output port (grid input pins), which are not used by benchmark */ std::vector cb_sides = rr_gsb.get_cb_ipin_sides(cb_type); @@ -154,6 +156,11 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, if (0 == ipin_node->fan_in) { continue; } + + /* Find the MUX instance that drives the IPIN! */ + std::string mux_instance_name = generate_cb_mux_instance_name(CONNECTION_BLOCK_MUX_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), inode, std::string("")); + mux_instance_to_net_map[mux_instance_name] = ipin_node->vpack_net_num; + vtr::Point port_coord(ipin_node->xlow, ipin_node->ylow); std::string port_name = generate_grid_side_port_name(grids, port_coord, @@ -185,100 +192,92 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, } } - /* TODO: Disable all the unused inputs of routing multiplexers, which are not used by benchmark */ - for (size_t side = 0; side < cb_sides.size(); ++side) { - enum e_side cb_ipin_side = cb_sides[side]; - for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) { - t_rr_node* ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode); - if (false == is_rr_node_to_be_disable_for_analysis(ipin_node)) { - continue; - } - if (0 == ipin_node->fan_in) { - continue; - } - vtr::Point port_coord(ipin_node->xlow, ipin_node->ylow); - std::string port_name = generate_grid_side_port_name(grids, - port_coord, - rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), - ipin_node->ptc_num); + /* Disable all the unused inputs of routing multiplexers, which are not used by benchmark + * Here, we start from each input of the Connection Blocks, and traverse forward to the sink + * port of the module net whose source is the input + * We will find the instance name which is the parent of the sink port, and search the + * net id through the instance_name_to_net_map + * The the net id does not match the net id of this input, we will disable the sink port! + * + * cb_module + * +----------------------- + * | MUX instance A + * | +----------- + * input_port--->|--+---x-->| sink port (disable!) + * | | +---------- + * | | MUX instance B + * | | +---------- + * | +------>| sink port (do not disable!) + */ + for (size_t itrack = 0; itrack < rr_gsb.get_cb_chan_width(cb_type); ++itrack) { + t_rr_node* chan_node = rr_gsb.get_chan_node(rr_gsb.get_cb_chan_side(cb_type), itrack); - /* Find the port in unique mirror! */ - if (true == compact_routing_hierarchy) { - /* Note: use GSB coordinate when inquire for unique modules!!! */ - DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y()); - const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord); - t_rr_node* unique_mirror_ipin_node = unique_mirror.get_ipin_node(cb_ipin_side, inode); - port_coord.set_x(unique_mirror_ipin_node->xlow); - port_coord.set_y(unique_mirror_ipin_node->ylow); - port_name = generate_grid_side_port_name(grids, - port_coord, - unique_mirror.get_ipin_node_grid_side(cb_ipin_side, inode), - unique_mirror_ipin_node->ptc_num); - } + /* Disable both input of the routing track if it is not used! */ + vtr::Point port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); + if (true == compact_routing_hierarchy) { + /* Note: use GSB coordinate when inquire for unique modules!!! */ + DeviceCoordinator cb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, cb_coord); + port_coord.set_x(unique_mirror.get_cb_x(cb_type)); + port_coord.set_y(unique_mirror.get_cb_y(cb_type)); + } + std::string port_name = generate_routing_track_port_name(cb_type, + port_coord, itrack, + OUT_PORT); - /* These codes are exactly same in build_routing_modules.cpp - * If you wish to change the naming rules, please change build_routing_modules.cpp as well - * so that consistency remains - */ - /* Build a vector of driver rr_nodes */ - std::vector drive_rr_nodes; - for (int jnode = 0; jnode < ipin_node->num_drive_rr_nodes; jnode++) { - drive_rr_nodes.push_back(ipin_node->drive_rr_nodes[jnode]); - } - - int switch_index = ipin_node->drive_switches[DEFAULT_SWITCH_ID]; - - /* Get the circuit model id of the routing multiplexer */ - CircuitModelId mux_model = rr_switches[switch_index].circuit_model; - - /* Find the input size of the implementation of a routing multiplexer */ - size_t datapath_mux_size = drive_rr_nodes.size(); - - /* Find the module name of the multiplexer and try to find it in the module manager */ - std::string mux_module_name = generate_mux_subckt_name(circuit_lib, mux_model, datapath_mux_size, std::string("")); - ModuleId mux_module = module_manager.find_module(mux_module_name); - VTR_ASSERT (true == module_manager.valid_module_id(mux_module)); + /* Ensure we have this port in the module! */ + ModulePortId module_port = module_manager.find_module_port(cb_module, port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port)); - /* Find the MUX instance that drives the IPIN! */ - std::string mux_instance_name = generate_cb_mux_instance_name(CONNECTION_BLOCK_MUX_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), inode, std::string("")); + /* Find the module net which sources from this port! */ + for (const size_t& pin : module_manager.module_port(cb_module, module_port).pins()) { + ModuleNetId module_net = module_manager.module_instance_port_net(cb_module, cb_module, 0, module_port, pin); + VTR_ASSERT(true == module_manager.valid_module_net_id(cb_module, module_net)); - /* Make sure this instance name exists! */ - size_t instance_id = module_manager.instance_id(cb_module, mux_module, mux_instance_name); - VTR_ASSERT(instance_id < module_manager.num_instance(cb_module, mux_module)); + /* Touch each sink of the net! */ + for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(cb_module, module_net)) { + ModuleId sink_module = module_manager.net_sink_modules(cb_module, module_net)[sink_id]; + size_t sink_instance = module_manager.net_sink_instances(cb_module, module_net)[sink_id]; - /* Find the MUX input port from model to module */ - std::vector mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true); - VTR_ASSERT(1 == mux_model_input_ports.size()); - /* Find the module port id of the input port */ - ModulePortId mux_input_port_id = module_manager.find_module_port(mux_module, circuit_lib.port_prefix(mux_model_input_ports[0])); - VTR_ASSERT(true == module_manager.valid_module_port_id(mux_module, mux_input_port_id)); - BasicPort mux_input_port = module_manager.module_port(mux_module, mux_input_port_id); - - /* Find out which routing path is used in this MUX */ - int path_id = DEFAULT_PATH_ID; - for (size_t jnode = 0; jnode < drive_rr_nodes.size(); ++jnode) { - if (drive_rr_nodes[jnode] == &(L_rr_node[ipin_node->prev_node])) { - path_id = (int)jnode; - break; + /* Skip when sink module is the cb module, + * the output ports of cb modules have been disabled/enabled already! + */ + if (sink_module == cb_module) { + continue; } - } - for (const size_t& pin : mux_input_port.pins()) { - if ((size_t)path_id == pin) { - continue; /* For used pin, skip disable timing */ + std::string sink_instance_name = module_manager.instance_name(cb_module, sink_module, sink_instance); + bool disable_timing = false; + /* Check if this node is used by benchmark */ + if (true == is_rr_node_to_be_disable_for_analysis(chan_node)) { + /* Disable all the sinks! */ + disable_timing = true; + } else { + /* See if the net id matches. If does not match, we should disable! */ + if (chan_node->vpack_net_num != mux_instance_to_net_map[sink_instance_name]) { + disable_timing = true; + } } + + /* Time to write SDC command to disable timing or not */ + if (false == disable_timing) { + continue; + } + + BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(cb_module, module_net)[sink_id]); + sink_port.set_width(module_manager.net_sink_pins(cb_module, module_net)[sink_id], + module_manager.net_sink_pins(cb_module, module_net)[sink_id]); /* Get the input id that is used! Disable the unused inputs! */ fp << "set_disable_timing "; fp << cb_instance_name << "/"; - fp << mux_instance_name << "/"; - fp << generate_sdc_port(BasicPort(mux_input_port.get_name(), pin, pin)); + fp << sink_instance_name << "/"; + fp << generate_sdc_port(sink_port); fp << std::endl; } } } } - /******************************************************************** * Iterate over all the connection blocks in a device * and disable unused ports for each of them @@ -286,10 +285,7 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, static void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp, const std::vector>& grids, - const std::vector& rr_switches, - t_rr_node* L_rr_node, const ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, const DeviceRRGSB& L_device_rr_gsb, const t_rr_type& cb_type, const bool& compact_routing_hierarchy) { @@ -307,9 +303,9 @@ void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp, continue; } - print_analysis_sdc_disable_cb_unused_resources(fp, grids, rr_switches, L_rr_node, + print_analysis_sdc_disable_cb_unused_resources(fp, grids, module_manager, - L_device_rr_gsb, circuit_lib, + L_device_rr_gsb, rr_gsb, cb_type, compact_routing_hierarchy); @@ -323,19 +319,16 @@ void print_analysis_sdc_disable_unused_cb_ports(std::fstream& fp, *******************************************************************/ void print_analysis_sdc_disable_unused_cbs(std::fstream& fp, const std::vector>& grids, - const std::vector& rr_switches, - t_rr_node* L_rr_node, const ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, const DeviceRRGSB& L_device_rr_gsb, const bool& compact_routing_hierarchy) { - print_analysis_sdc_disable_unused_cb_ports(fp, grids, rr_switches, L_rr_node, module_manager, - circuit_lib, L_device_rr_gsb, + print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager, + L_device_rr_gsb, CHANX, compact_routing_hierarchy); - print_analysis_sdc_disable_unused_cb_ports(fp, grids, rr_switches, L_rr_node, module_manager, - circuit_lib, L_device_rr_gsb, + print_analysis_sdc_disable_unused_cb_ports(fp, grids, module_manager, + L_device_rr_gsb, CHANY, compact_routing_hierarchy); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h index d05fcf226..21154b1d8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h @@ -9,10 +9,7 @@ void print_analysis_sdc_disable_unused_cbs(std::fstream& fp, const std::vector>& grids, - const std::vector& rr_switches, - t_rr_node* L_rr_node, const ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, const DeviceRRGSB& L_device_rr_gsb, const bool& compact_routing_hierarchy); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp index 1ee475e16..5d2a15b7a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp @@ -195,8 +195,6 @@ void print_analysis_sdc(const std::string& sdc_dir, const std::vector& L_logical_blocks, const vtr::Point& device_size, const std::vector>& L_grids, - const std::vector& rr_switches, - t_rr_node* L_rr_node, const std::vector& L_blocks, const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, @@ -245,9 +243,8 @@ void print_analysis_sdc(const std::string& sdc_dir, /* TODO: Disable timing for unused routing resources in connection blocks */ - print_analysis_sdc_disable_unused_cbs(fp, L_grids, rr_switches, L_rr_node, + print_analysis_sdc_disable_unused_cbs(fp, L_grids, module_manager, - circuit_lib, L_device_rr_gsb, compact_routing_hierarchy); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h index aeb55247d..252c76c71 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.h @@ -13,8 +13,6 @@ void print_analysis_sdc(const std::string& sdc_dir, const std::vector& L_logical_blocks, const vtr::Point& device_size, const std::vector>& L_grids, - const std::vector& rr_switches, - t_rr_node* L_rr_node, const std::vector& L_blocks, const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp index e3666051a..83683db1f 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.cpp @@ -14,7 +14,6 @@ void fpga_sdc_generator(const SdcOption& sdc_options, const float& critical_path_delay, const std::vector>& grids, const std::vector& rr_switches, - t_rr_node* L_rr_node, const DeviceRRGSB& L_device_rr_gsb, const std::vector& L_logical_blocks, const vtr::Point& device_size, @@ -43,7 +42,7 @@ void fpga_sdc_generator(const SdcOption& sdc_options, print_analysis_sdc(sdc_options.sdc_dir(), critical_path_delay, L_device_rr_gsb, - L_logical_blocks, device_size, L_grids, rr_switches, L_rr_node, + L_logical_blocks, device_size, L_grids, L_blocks, module_manager, circuit_lib, global_ports, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h index 51f0beb64..402d65bed 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/sdc_api.h @@ -11,7 +11,6 @@ void fpga_sdc_generator(const SdcOption& sdc_options, const float& critical_path_delay, const std::vector>& grids, const std::vector& rr_switches, - t_rr_node* L_rr_node, const DeviceRRGSB& L_device_rr_gsb, const std::vector& L_logical_blocks, const vtr::Point& device_size, 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 0a2ba84cf..edff64348 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 @@ -159,7 +159,7 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup, /* 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, - grids, rr_switches, rr_node, device_rr_gsb, + grids, rr_switches, device_rr_gsb, L_logical_blocks, device_size, grids, L_blocks, module_manager, mux_lib, Arch.spice->circuit_lib, global_ports, From 5f219b428cf3d623a79d9e27ea39419f4d1fa6d7 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 11 Nov 2019 19:24:39 -0700 Subject: [PATCH 61/68] refactored analysis SDC generation for switch blocks --- .../analysis_sdc_routing_writer.cpp | 411 +++++++++++++++--- .../analysis_sdc_routing_writer.h | 7 + .../backend_assistant/analysis_sdc_writer.cpp | 17 +- 3 files changed, 374 insertions(+), 61 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp index 48a798aab..312696456 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp @@ -37,6 +37,84 @@ bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node) { return true; } +/******************************************************************** + * Disable all the unused inputs of routing multiplexers, which are not used by benchmark + * Here, we start from each input of a routing module, and traverse forward to the sink + * port of the module net whose source is the input + * We will find the instance name which is the parent of the sink port, and search the + * net id through the instance_name_to_net_map + * The the net id does not match the net id of this input, we will disable the sink port! + * + * parent_module + * +----------------------- + * | MUX instance A + * | +----------- + * input_port--->|--+---x-->| sink port (disable! net_id = Y) + * (net_id = X) | | +---------- + * | | MUX instance B + * | | +---------- + * | +------>| sink port (do not disable! net_id = X) + * + *******************************************************************/ +static +void disable_analysis_module_input_port_net_sinks(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& parent_instance_name, + const ModulePortId& module_input_port, + t_rr_node* input_rr_node, + const std::map mux_instance_to_net_map) { + /* Validate file stream */ + check_file_handler(fp); + + /* Find the module net which sources from this port! */ + for (const size_t& pin : module_manager.module_port(parent_module, module_input_port).pins()) { + ModuleNetId module_net = module_manager.module_instance_port_net(parent_module, parent_module, 0, module_input_port, pin); + VTR_ASSERT(true == module_manager.valid_module_net_id(parent_module, module_net)); + + /* Touch each sink of the net! */ + for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(parent_module, module_net)) { + ModuleId sink_module = module_manager.net_sink_modules(parent_module, module_net)[sink_id]; + size_t sink_instance = module_manager.net_sink_instances(parent_module, module_net)[sink_id]; + + /* Skip when sink module is the parent module, + * the output ports of parent modules have been disabled/enabled already! + */ + if (sink_module == parent_module) { + continue; + } + + std::string sink_instance_name = module_manager.instance_name(parent_module, sink_module, sink_instance); + bool disable_timing = false; + /* Check if this node is used by benchmark */ + if (true == is_rr_node_to_be_disable_for_analysis(input_rr_node)) { + /* Disable all the sinks! */ + disable_timing = true; + } else { + /* See if the net id matches. If does not match, we should disable! */ + if (input_rr_node->vpack_net_num != mux_instance_to_net_map.at(sink_instance_name)) { + disable_timing = true; + } + } + + /* Time to write SDC command to disable timing or not */ + if (false == disable_timing) { + continue; + } + + BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(parent_module, module_net)[sink_id]); + sink_port.set_width(module_manager.net_sink_pins(parent_module, module_net)[sink_id], + module_manager.net_sink_pins(parent_module, module_net)[sink_id]); + /* Get the input id that is used! Disable the unused inputs! */ + fp << "set_disable_timing "; + fp << parent_instance_name << "/"; + fp << sink_instance_name << "/"; + fp << generate_sdc_port(sink_port); + fp << std::endl; + } + } +} + /******************************************************************** * This function will disable * 1. all the unused port (unmapped by a benchmark) of a connection block @@ -150,6 +228,11 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, enum e_side cb_ipin_side = cb_sides[side]; for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) { t_rr_node* ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode); + + /* Find the MUX instance that drives the IPIN! */ + std::string mux_instance_name = generate_cb_mux_instance_name(CONNECTION_BLOCK_MUX_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), inode, std::string("")); + mux_instance_to_net_map[mux_instance_name] = ipin_node->vpack_net_num; + if (false == is_rr_node_to_be_disable_for_analysis(ipin_node)) { continue; } @@ -157,10 +240,6 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, continue; } - /* Find the MUX instance that drives the IPIN! */ - std::string mux_instance_name = generate_cb_mux_instance_name(CONNECTION_BLOCK_MUX_INSTANCE_PREFIX, rr_gsb.get_ipin_node_grid_side(cb_ipin_side, inode), inode, std::string("")); - mux_instance_to_net_map[mux_instance_name] = ipin_node->vpack_net_num; - vtr::Point port_coord(ipin_node->xlow, ipin_node->ylow); std::string port_name = generate_grid_side_port_name(grids, port_coord, @@ -229,52 +308,12 @@ void print_analysis_sdc_disable_cb_unused_resources(std::fstream& fp, ModulePortId module_port = module_manager.find_module_port(cb_module, port_name); VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, module_port)); - /* Find the module net which sources from this port! */ - for (const size_t& pin : module_manager.module_port(cb_module, module_port).pins()) { - ModuleNetId module_net = module_manager.module_instance_port_net(cb_module, cb_module, 0, module_port, pin); - VTR_ASSERT(true == module_manager.valid_module_net_id(cb_module, module_net)); - - /* Touch each sink of the net! */ - for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(cb_module, module_net)) { - ModuleId sink_module = module_manager.net_sink_modules(cb_module, module_net)[sink_id]; - size_t sink_instance = module_manager.net_sink_instances(cb_module, module_net)[sink_id]; - - /* Skip when sink module is the cb module, - * the output ports of cb modules have been disabled/enabled already! - */ - if (sink_module == cb_module) { - continue; - } - - std::string sink_instance_name = module_manager.instance_name(cb_module, sink_module, sink_instance); - bool disable_timing = false; - /* Check if this node is used by benchmark */ - if (true == is_rr_node_to_be_disable_for_analysis(chan_node)) { - /* Disable all the sinks! */ - disable_timing = true; - } else { - /* See if the net id matches. If does not match, we should disable! */ - if (chan_node->vpack_net_num != mux_instance_to_net_map[sink_instance_name]) { - disable_timing = true; - } - } - - /* Time to write SDC command to disable timing or not */ - if (false == disable_timing) { - continue; - } - - BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(cb_module, module_net)[sink_id]); - sink_port.set_width(module_manager.net_sink_pins(cb_module, module_net)[sink_id], - module_manager.net_sink_pins(cb_module, module_net)[sink_id]); - /* Get the input id that is used! Disable the unused inputs! */ - fp << "set_disable_timing "; - fp << cb_instance_name << "/"; - fp << sink_instance_name << "/"; - fp << generate_sdc_port(sink_port); - fp << std::endl; - } - } + disable_analysis_module_input_port_net_sinks(fp, + module_manager, cb_module, + cb_instance_name, + module_port, + chan_node, + mux_instance_to_net_map); } } @@ -332,3 +371,275 @@ void print_analysis_sdc_disable_unused_cbs(std::fstream& fp, CHANY, compact_routing_hierarchy); } +/******************************************************************** + * This function will disable + * 1. all the unused port (unmapped by a benchmark) of a switch block + * 2. all the unused inputs (unmapped by a benchmark) of routing multiplexers + * in a switch block + *******************************************************************/ +static +void print_analysis_sdc_disable_sb_unused_resources(std::fstream& fp, + const std::vector>& grids, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const RRGSB& rr_gsb, + const bool& compact_routing_hierarchy) { + /* Validate file stream */ + check_file_handler(fp); + + vtr::Point gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); + + std::string sb_instance_name = generate_switch_block_module_name(gsb_coordinate); + + /* If we use the compact routing hierarchy, we need to find the module name !*/ + vtr::Point sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); + if (true == compact_routing_hierarchy) { + DeviceCoordinator sb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + /* Note: use GSB coordinate when inquire for unique modules!!! */ + const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(sb_coord); + sb_coordinate.set_x(unique_mirror.get_sb_x()); + sb_coordinate.set_y(unique_mirror.get_sb_y()); + } + + std::string sb_module_name = generate_switch_block_module_name(sb_coordinate); + + ModuleId sb_module = module_manager.find_module(sb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); + + /* Print comments */ + fp << "##################################################" << std::endl; + fp << "# Disable timing for Switch block " << sb_module_name << std::endl; + fp << "##################################################" << std::endl; + + /* Build a map between mux_instance name and net_num */ + std::map mux_instance_to_net_map; + + /* Disable all the input/output port (routing tracks), which are not used by benchmark */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + DeviceCoordinator port_coordinate = rr_gsb.get_side_block_coordinator(side_manager.get_side()); + + for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) { + t_rr_node* chan_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack); + + vtr::Point port_coord(port_coordinate.get_x(), port_coordinate.get_y()); + std::string port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(side_manager.get_side(), itrack)->type, + port_coord, itrack, + rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)); + + if (true == compact_routing_hierarchy) { + /* Note: use GSB coordinate when inquire for unique modules!!! */ + DeviceCoordinator sb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(sb_coord); + DeviceCoordinator unique_port_coordinate = unique_mirror.get_side_block_coordinator(side_manager.get_side()); + port_coord.set_x(unique_port_coordinate.get_x()); + port_coord.set_y(unique_port_coordinate.get_y()); + port_name = generate_routing_track_port_name(unique_mirror.get_chan_node(side_manager.get_side(), itrack)->type, + port_coord, itrack, + unique_mirror.get_chan_node_direction(side_manager.get_side(), itrack)); + } + + /* Ensure we have this port in the module! */ + ModulePortId module_port = module_manager.find_module_port(sb_module, port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, module_port)); + + /* Cache the net name for routing tracks which are outputs of the switch block */ + if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { + /* Generate the name of mux instance related to this output node */ + std::string mux_instance_name = generate_sb_memory_instance_name(SWITCH_BLOCK_MUX_INSTANCE_PREFIX, side_manager.get_side(), itrack, std::string("")); + mux_instance_to_net_map[mux_instance_name] = chan_node->vpack_net_num; + } + + /* Check if this node is used by benchmark */ + if (false == is_rr_node_to_be_disable_for_analysis(chan_node)) { + continue; + } + + fp << "set_disable_timing "; + fp << sb_instance_name << "/"; + fp << generate_sdc_port(module_manager.module_port(sb_module, module_port)); + fp << std::endl; + } + } + + /* Disable all the input port (grid output pins), which are not used by benchmark */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + + for (size_t inode = 0; inode < rr_gsb.get_num_opin_nodes(side_manager.get_side()); ++inode) { + t_rr_node* opin_node = rr_gsb.get_opin_node(side_manager.get_side(), inode); + vtr::Point port_coord(rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, + rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow); + + std::string port_name = generate_grid_side_port_name(grids, port_coord, + rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode), + opin_node->ptc_num); + + if (true == compact_routing_hierarchy) { + /* Note: use GSB coordinate when inquire for unique modules!!! */ + DeviceCoordinator sb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(sb_coord); + port_coord.set_x(unique_mirror.get_opin_node(side_manager.get_side(), inode)->xlow); + port_coord.set_y(unique_mirror.get_opin_node(side_manager.get_side(), inode)->ylow); + + port_name = generate_grid_side_port_name(grids, port_coord, + unique_mirror.get_opin_node_grid_side(side_manager.get_side(), inode), + unique_mirror.get_opin_node(side_manager.get_side(), inode)->ptc_num); + } + + + /* Ensure we have this port in the module! */ + ModulePortId module_port = module_manager.find_module_port(sb_module, port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, module_port)); + + /* Check if this node is used by benchmark */ + if (false == is_rr_node_to_be_disable_for_analysis(opin_node)) { + continue; + } + + fp << "set_disable_timing "; + fp << sb_instance_name << "/"; + fp << generate_sdc_port(module_manager.module_port(sb_module, module_port)); + fp << std::endl; + } + } + + /* Disable all the unused inputs of routing multiplexers, which are not used by benchmark + * Here, we start from each input of the Switch Blocks, and traverse forward to the sink + * port of the module net whose source is the input + * We will find the instance name which is the parent of the sink port, and search the + * net id through the instance_name_to_net_map + * The the net id does not match the net id of this input, we will disable the sink port! + * + * sb_module + * +----------------------- + * | MUX instance A + * | +----------- + * input_port--->|--+---x-->| sink port (disable! net_id = Y) + * (net_id = X) | | +---------- + * | | MUX instance B + * | | +---------- + * | +------>| sink port (do not disable! net_id = X) + * + * Because the input ports of a SB module come from + * 1. Grid output pins + * 2. routing tracks + * We will walk through these ports and do conditionally disable_timing + */ + + /* Iterate over input ports coming from grid output pins */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + + for (size_t inode = 0; inode < rr_gsb.get_num_opin_nodes(side_manager.get_side()); ++inode) { + t_rr_node* opin_node = rr_gsb.get_opin_node(side_manager.get_side(), inode); + vtr::Point port_coord(rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, + rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow); + + std::string port_name = generate_grid_side_port_name(grids, port_coord, + rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode), + opin_node->ptc_num); + + if (true == compact_routing_hierarchy) { + /* Note: use GSB coordinate when inquire for unique modules!!! */ + DeviceCoordinator sb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(sb_coord); + port_coord.set_x(unique_mirror.get_opin_node(side_manager.get_side(), inode)->xlow); + port_coord.set_y(unique_mirror.get_opin_node(side_manager.get_side(), inode)->ylow); + + port_name = generate_grid_side_port_name(grids, port_coord, + unique_mirror.get_opin_node_grid_side(side_manager.get_side(), inode), + unique_mirror.get_opin_node(side_manager.get_side(), inode)->ptc_num); + } + + + /* Ensure we have this port in the module! */ + ModulePortId module_port = module_manager.find_module_port(sb_module, port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, module_port)); + + disable_analysis_module_input_port_net_sinks(fp, module_manager, + sb_module, + sb_instance_name, + module_port, + opin_node, + mux_instance_to_net_map); + } + } + + /* Iterate over input ports coming from routing tracks */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + DeviceCoordinator port_coordinate = rr_gsb.get_side_block_coordinator(side_manager.get_side()); + + for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) { + /* Skip output ports, they have already been disabled or not */ + if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { + continue; + } + + t_rr_node* chan_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack); + + vtr::Point port_coord(port_coordinate.get_x(), port_coordinate.get_y()); + std::string port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(side_manager.get_side(), itrack)->type, + port_coord, itrack, + rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)); + + if (true == compact_routing_hierarchy) { + /* Note: use GSB coordinate when inquire for unique modules!!! */ + DeviceCoordinator sb_coord(rr_gsb.get_x(), rr_gsb.get_y()); + const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(sb_coord); + DeviceCoordinator unique_port_coordinate = unique_mirror.get_side_block_coordinator(side_manager.get_side()); + port_coord.set_x(unique_port_coordinate.get_x()); + port_coord.set_y(unique_port_coordinate.get_y()); + + port_name = generate_routing_track_port_name(unique_mirror.get_chan_node(side_manager.get_side(), itrack)->type, + port_coord, itrack, + unique_mirror.get_chan_node_direction(side_manager.get_side(), itrack)); + } + + + /* Ensure we have this port in the module! */ + ModulePortId module_port = module_manager.find_module_port(sb_module, port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, module_port)); + + disable_analysis_module_input_port_net_sinks(fp, module_manager, + sb_module, + sb_instance_name, + module_port, + chan_node, + mux_instance_to_net_map); + } + } +} + + +/******************************************************************** + * Iterate over all the connection blocks in a device + * and disable unused ports for each of them + *******************************************************************/ +void print_analysis_sdc_disable_unused_sbs(std::fstream& fp, + const std::vector>& grids, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const bool& compact_routing_hierarchy) { + + /* Build unique X-direction connection block modules */ + DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range(); + + for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { + /* Check if the connection block exists in the device! + * Some of them do NOT exist due to heterogeneous blocks (height > 1) + * We will skip those modules + */ + const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); + + print_analysis_sdc_disable_sb_unused_resources(fp, grids, + module_manager, + L_device_rr_gsb, + rr_gsb, + compact_routing_hierarchy); + } + } +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h index 21154b1d8..4b8fcc033 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.h @@ -12,4 +12,11 @@ void print_analysis_sdc_disable_unused_cbs(std::fstream& fp, const ModuleManager& module_manager, const DeviceRRGSB& L_device_rr_gsb, const bool& compact_routing_hierarchy); + +void print_analysis_sdc_disable_unused_sbs(std::fstream& fp, + const std::vector>& grids, + const ModuleManager& module_manager, + const DeviceRRGSB& L_device_rr_gsb, + const bool& compact_routing_hierarchy); + #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp index 5d2a15b7a..41200c354 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp @@ -242,22 +242,17 @@ void print_analysis_sdc(const std::string& sdc_dir, format_dir_path(module_manager.module_name(top_module))); - /* TODO: Disable timing for unused routing resources in connection blocks */ + /* Disable timing for unused routing resources in connection blocks */ print_analysis_sdc_disable_unused_cbs(fp, L_grids, module_manager, L_device_rr_gsb, compact_routing_hierarchy); - /* TODO: Disable timing for unused routing resources in switch blocks */ - /* - if (TRUE == compact_routing_hierarchy) { - verilog_generate_sdc_disable_unused_sbs(fp); - verilog_generate_sdc_disable_unused_sbs_muxs(fp); - } else { - verilog_generate_sdc_disable_unused_sbs(fp, LL_nx, LL_ny); - verilog_generate_sdc_disable_unused_sbs_muxs(fp, LL_nx, LL_ny); - } - */ + /* Disable timing for unused routing resources in switch blocks */ + print_analysis_sdc_disable_unused_sbs(fp, L_grids, + module_manager, + L_device_rr_gsb, + compact_routing_hierarchy); /* TODO: Disable timing for unused routing resources in grids (programmable blocks) */ /* From 8a57a29d2d4aaf35c130d5120ce2dac36d614270 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 11 Nov 2019 22:38:11 -0700 Subject: [PATCH 62/68] refactoring analysis SDC generation for grids --- .../analysis_sdc_grid_writer.cpp | 200 ++++++++++++++++++ .../analysis_sdc_grid_writer.h | 16 ++ .../backend_assistant/analysis_sdc_writer.cpp | 6 +- 3 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp new file mode 100644 index 000000000..90a58c91c --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp @@ -0,0 +1,200 @@ +/******************************************************************** + * This file includes functions that are used to write SDC commands + * to disable unused ports of grids, such as Configurable Logic Block + * (CLBs), heterogeneous blocks, etc. + *******************************************************************/ +#include "vtr_assert.h" + +#include "fpga_x2p_reserved_words.h" +#include "fpga_x2p_naming.h" +#include "fpga_x2p_utils.h" + +#include "analysis_sdc_grid_writer.h" + +#include "globals.h" + +/******************************************************************** + * Disable the timing for a fully unused grid! + * This is very straightforward! + * Just walk through each pb_type and disable all the ports using wildcards + *******************************************************************/ +static +void print_analysis_sdc_disable_unused_pb_type(std::fstream& fp, + t_type_ptr grid_type, + const vtr::Point& grid_coordinate, + const ModuleManager& module_manager, + const size_t& grid_z, + const e_side& border_side) { + /* Check code: if this is an IO block, the border side MUST be valid */ + if (IO_TYPE == grid_type) { + VTR_ASSERT(NUM_SIDES != border_side); + } + + /* Find an unique name to the grid instane + * Note: this must be consistent with the instance name we used in build_top_module()!!! + */ + std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX); + std::string grid_instance_name = generate_grid_block_instance_name(grid_module_name_prefix, std::string(grid_type->name), IO_TYPE == grid_type, border_side, grid_coordinate); + + /* Find an unique name to the pb instance in this grid + * Note: this must be consistent with the instance name we used in build_grid_module()!!! + */ + std::string pb_module_name_prefix(GRID_MODULE_NAME_PREFIX); + std::string pb_instance_name = generate_grid_physical_block_instance_name(pb_module_name_prefix, grid_type->pb_graph_head->pb_type, border_side, grid_z); + + /* Print comments */ + fp << "#######################################" << std::endl; + fp << "# Disable Timing for unused grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "][" << grid_z << "]" << std::endl; + fp << "#######################################" << std::endl; + + /* Disable everything under this level using wildcard */ + fp << "set_disable_timing "; + fp << grid_instance_name; + fp << "/"; + fp << pb_instance_name; + fp << "/*"; + fp << std::endl; + + /* TODO: Go recursively through the pb_graph hierarchy, and disable all the ports level by level */ + /* + rec_verilog_generate_sdc_disable_unused_pb_types(fp, prefix, + cur_grid_type->pb_type); + */ +} + +/******************************************************************** + * Disable the timing for a fully unused grid! + * This is very straightforward! + * Just walk through each pb_type and disable all the ports using wildcards + *******************************************************************/ +static +void print_analysis_sdc_disable_unused_grid(std::fstream& fp, + const vtr::Point& grid_coordinate, + const std::vector>& L_grids, + const std::vector& L_blocks, + const ModuleManager& module_manager, + const e_side& border_side) { + /* Validate file stream */ + check_file_handler(fp); + + t_type_ptr type = L_grids[grid_coordinate.x()][grid_coordinate.y()].type; + /* Bypass conditions for grids : + * 1. EMPTY type, which is by nature unused + * 2. Offset > 0, which has already been processed when offset = 0 + */ + if ( (NULL == type) + || (EMPTY_TYPE == type) + || (0 == L_grids[grid_coordinate.x()][grid_coordinate.y()].offset) ) { + return; + } + + /* Now we need to find the usage of this grid */ + std::vector grid_usage(type->capacity, false); + + /* Print comments */ + fp << "#######################################" << std::endl; + fp << "# Disable Timing for grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "]" << std::endl; + fp << "#######################################" << std::endl; + + /* For used grid, find the unused rr_node in the local rr_graph + * and then disable each port which is not used + * as well as the unused inputs of routing multiplexers! + */ + for (int iblk = 0; iblk < L_grids[grid_coordinate.x()][grid_coordinate.y()].usage; ++iblk) { + int blk_id = L_grids[grid_coordinate.x()][grid_coordinate.y()].blocks[iblk]; + VTR_ASSERT( (OPEN < L_blocks[blk_id].z) && (L_blocks[blk_id].z < type->capacity) ); + /* Mark the grid_usage */ + grid_usage[L_blocks[blk_id].z] = true; + /* TODO: + verilog_generate_sdc_disable_one_unused_block(fp, &(L_blocks[blk_id])); + */ + } + + /* For unused grid, disable all the pins in the physical_pb_type */ + for (int iblk = 0; iblk < type->capacity; ++iblk) { + /* Bypass used blocks */ + if (true == grid_usage[iblk]) { + continue; + } + print_analysis_sdc_disable_unused_pb_type(fp, type, grid_coordinate, module_manager, iblk, border_side); + } +} + +/******************************************************************** + * Top-level function writes SDC commands to disable unused ports + * of grids, such as Configurable Logic Block (CLBs), heterogeneous blocks, etc. + * + * This function will iterate over all the grids available in the FPGA fabric + * It will disable the timing analysis for + * 1. Grids, which are totally not used (no logic has been mapped to) + * 2. Unused part of grids, including the ports, inputs of routing multiplexers + * + * Note that it is a must to disable the unused inputs of routing multiplexers + * because it will cause unexpected paths in timing analysis + * For example: + * +---------------------+ + * inputA (net0) ------->| | + * | Routing multiplexer |----> output (net0) + * inputB (net1) ------->| | + * +---------------------+ + * + * During timing analysis, the path from inputA to output should be considered + * while the path from inputB to output should NOT be considered!!! + * + *******************************************************************/ +void print_analysis_sdc_disable_unused_grids(std::fstream& fp, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, + const ModuleManager& module_manager) { + /* TODO: disable inputs of multiplexers + verilog_generate_sdc_disable_unused_grids_muxs(fp, LL_nx, LL_ny, LL_grid, LL_block); + */ + + /* Process unused core grids */ + for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { + for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { + /* We should not meet any I/O grid */ + VTR_ASSERT(IO_TYPE != L_grids[ix][iy].type); + + print_analysis_sdc_disable_unused_grid(fp, vtr::Point(ix, iy), + L_grids, L_blocks, module_manager, NUM_SIDES); + } + } + + /* Instanciate I/O grids */ + /* Create the coordinate range for each side of FPGA fabric */ + std::vector io_sides{TOP, RIGHT, BOTTOM, LEFT}; + std::map>> io_coordinates; + + /* TOP side*/ + for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { + io_coordinates[TOP].push_back(vtr::Point(ix, device_size.y() - 1)); + } + + /* RIGHT side */ + for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { + io_coordinates[RIGHT].push_back(vtr::Point(device_size.x() - 1, iy)); + } + + /* BOTTOM side*/ + for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { + io_coordinates[BOTTOM].push_back(vtr::Point(ix, 0)); + } + + /* LEFT side */ + for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { + io_coordinates[LEFT].push_back(vtr::Point(0, iy)); + } + + /* Add instances of I/O grids to top_module */ + for (const e_side& io_side : io_sides) { + for (const vtr::Point& io_coordinate : io_coordinates[io_side]) { + /* We should not meet any I/O grid */ + VTR_ASSERT(IO_TYPE == L_grids[io_coordinate.x()][io_coordinate.y()].type); + + print_analysis_sdc_disable_unused_grid(fp, io_coordinate, + L_grids, L_blocks, module_manager, io_side); + } + } +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.h new file mode 100644 index 000000000..a198cc129 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.h @@ -0,0 +1,16 @@ +#ifndef ANALYSIS_SDC_GRID_WRITER_H +#define ANALYSIS_SDC_GRID_WRITER_H + +#include +#include +#include "vtr_geometry.h" +#include "vpr_types.h" +#include "module_manager.h" + +void print_analysis_sdc_disable_unused_grids(std::fstream& fp, + const vtr::Point& device_size, + const std::vector>& L_grids, + const std::vector& L_blocks, + const ModuleManager& module_manager); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp index 41200c354..8aed25fc0 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp @@ -20,6 +20,7 @@ #include "sdc_writer_utils.h" #include "sdc_memory_utils.h" +#include "analysis_sdc_grid_writer.h" #include "analysis_sdc_routing_writer.h" #include "analysis_sdc_writer.h" @@ -255,10 +256,7 @@ void print_analysis_sdc(const std::string& sdc_dir, compact_routing_hierarchy); /* TODO: Disable timing for unused routing resources in grids (programmable blocks) */ - /* - verilog_generate_sdc_disable_unused_grids(fp, LL_nx, LL_ny, LL_grid, LL_block); - verilog_generate_sdc_disable_unused_grids_muxs(fp, LL_nx, LL_ny, LL_grid, LL_block); - */ + print_analysis_sdc_disable_unused_grids(fp, device_size, L_grids, L_blocks, module_manager); /* Close file handler */ fp.close(); From 6c58a4dd9226a2892f88af0b8dfb1fad708f4649 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 12 Nov 2019 10:01:17 -0700 Subject: [PATCH 63/68] refactored unused grid block SDC analysis generation --- .../analysis_sdc_grid_writer.cpp | 124 +++++++++++++----- .../module_builder/build_grid_modules.cpp | 2 +- 2 files changed, 93 insertions(+), 33 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp index 90a58c91c..2a491f129 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp @@ -8,58 +8,107 @@ #include "fpga_x2p_reserved_words.h" #include "fpga_x2p_naming.h" #include "fpga_x2p_utils.h" +#include "fpga_x2p_pbtypes_utils.h" #include "analysis_sdc_grid_writer.h" #include "globals.h" +/******************************************************************** + * Recursively visit all the pb_types in the hierarchy + * and disable all the ports + * + * Note: it is a must to disable all the ports in all the child pb_types! + * This can prohibit timing analyzer to consider any FF-to-FF path or + * combinatinal path inside an unused grid, when finding critical paths!!! + *******************************************************************/ +static +void rec_print_analysis_sdc_disable_unused_pb_graph_nodes(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& hierarchy_name, + t_pb_graph_node* physical_pb_graph_node, + const e_side& border_side) { + t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type; + + /* Disable all the ports of current module (parent_module)! + * Hierarchy name already includes the instance name of parent_module + */ + fp << "set_disable_timing "; + fp << hierarchy_name; + fp << "/*"; + fp << std::endl; + + /* Return if this is the primitive pb_type */ + if (TRUE == is_primitive_pb_type(physical_pb_type)) { + return; + } + + /* Go recursively */ + int physical_mode_index = find_pb_type_physical_mode_index(*physical_pb_type); + + /* Disable all the ports by iterating over its instance in the parent module */ + for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) { + /* Generate the name of the Verilog module for this child */ + std::string child_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side); + std::string child_module_name = generate_physical_block_module_name(child_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild])); + + ModuleId child_module = module_manager.find_module(child_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(child_module)); + + /* Each child may exist multiple times in the hierarchy*/ + for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) { + std::string child_instance_name = module_manager.instance_name(parent_module, child_module, module_manager.child_module_instances(parent_module, child_module)[inst]); + /* Must have a valid instance name!!! */ + VTR_ASSERT(false == child_instance_name.empty()); + + std::string updated_hierarchy_name = hierarchy_name + std::string("/") + child_instance_name + std::string("/"); + + rec_print_analysis_sdc_disable_unused_pb_graph_nodes(fp, module_manager, child_module, hierarchy_name, + &(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]), + border_side); + } + } +} + /******************************************************************** * Disable the timing for a fully unused grid! * This is very straightforward! * Just walk through each pb_type and disable all the ports using wildcards *******************************************************************/ static -void print_analysis_sdc_disable_unused_pb_type(std::fstream& fp, - t_type_ptr grid_type, - const vtr::Point& grid_coordinate, - const ModuleManager& module_manager, - const size_t& grid_z, - const e_side& border_side) { +void print_analysis_sdc_disable_unused_pb_block(std::fstream& fp, + t_type_ptr grid_type, + const vtr::Point& grid_coordinate, + const ModuleManager& module_manager, + const std::string& grid_instance_name, + const size_t& grid_z, + const e_side& border_side) { /* Check code: if this is an IO block, the border side MUST be valid */ if (IO_TYPE == grid_type) { VTR_ASSERT(NUM_SIDES != border_side); } - /* Find an unique name to the grid instane - * Note: this must be consistent with the instance name we used in build_top_module()!!! - */ - std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX); - std::string grid_instance_name = generate_grid_block_instance_name(grid_module_name_prefix, std::string(grid_type->name), IO_TYPE == grid_type, border_side, grid_coordinate); - /* Find an unique name to the pb instance in this grid * Note: this must be consistent with the instance name we used in build_grid_module()!!! */ + /* TODO: validate that the instance name is used in module manager!!! */ std::string pb_module_name_prefix(GRID_MODULE_NAME_PREFIX); + std::string pb_module_name = generate_grid_physical_block_module_name(pb_module_name_prefix, grid_type->pb_graph_head->pb_type, border_side); std::string pb_instance_name = generate_grid_physical_block_instance_name(pb_module_name_prefix, grid_type->pb_graph_head->pb_type, border_side, grid_z); + ModuleId pb_module = module_manager.find_module(pb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(pb_module)); + /* Print comments */ fp << "#######################################" << std::endl; fp << "# Disable Timing for unused grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "][" << grid_z << "]" << std::endl; fp << "#######################################" << std::endl; - - /* Disable everything under this level using wildcard */ - fp << "set_disable_timing "; - fp << grid_instance_name; - fp << "/"; - fp << pb_instance_name; - fp << "/*"; - fp << std::endl; - /* TODO: Go recursively through the pb_graph hierarchy, and disable all the ports level by level */ - /* - rec_verilog_generate_sdc_disable_unused_pb_types(fp, prefix, - cur_grid_type->pb_type); - */ + std::string hierarchy_name = grid_instance_name + std::string("/") + pb_instance_name + std::string("/"); + + /* Go recursively through the pb_graph hierarchy, and disable all the ports level by level */ + rec_print_analysis_sdc_disable_unused_pb_graph_nodes(fp, module_manager, pb_module, hierarchy_name, grid_type->pb_graph_head, border_side); } /******************************************************************** @@ -77,19 +126,30 @@ void print_analysis_sdc_disable_unused_grid(std::fstream& fp, /* Validate file stream */ check_file_handler(fp); - t_type_ptr type = L_grids[grid_coordinate.x()][grid_coordinate.y()].type; + t_type_ptr grid_type = L_grids[grid_coordinate.x()][grid_coordinate.y()].type; /* Bypass conditions for grids : * 1. EMPTY type, which is by nature unused * 2. Offset > 0, which has already been processed when offset = 0 */ - if ( (NULL == type) - || (EMPTY_TYPE == type) + if ( (NULL == grid_type) + || (EMPTY_TYPE == grid_type) || (0 == L_grids[grid_coordinate.x()][grid_coordinate.y()].offset) ) { return; } + /* Find an unique name to the grid instane + * Note: this must be consistent with the instance name we used in build_top_module()!!! + */ + /* TODO: validate that the instance name is used in module manager!!! */ + std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX); + std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), IO_TYPE == grid_type, border_side); + std::string grid_instance_name = generate_grid_block_instance_name(grid_module_name_prefix, std::string(grid_type->name), IO_TYPE == grid_type, border_side, grid_coordinate); + + ModuleId grid_module = module_manager.find_module(grid_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(grid_module)); + /* Now we need to find the usage of this grid */ - std::vector grid_usage(type->capacity, false); + std::vector grid_usage(grid_type->capacity, false); /* Print comments */ fp << "#######################################" << std::endl; @@ -102,7 +162,7 @@ void print_analysis_sdc_disable_unused_grid(std::fstream& fp, */ for (int iblk = 0; iblk < L_grids[grid_coordinate.x()][grid_coordinate.y()].usage; ++iblk) { int blk_id = L_grids[grid_coordinate.x()][grid_coordinate.y()].blocks[iblk]; - VTR_ASSERT( (OPEN < L_blocks[blk_id].z) && (L_blocks[blk_id].z < type->capacity) ); + VTR_ASSERT( (OPEN < L_blocks[blk_id].z) && (L_blocks[blk_id].z < grid_type->capacity) ); /* Mark the grid_usage */ grid_usage[L_blocks[blk_id].z] = true; /* TODO: @@ -111,12 +171,12 @@ void print_analysis_sdc_disable_unused_grid(std::fstream& fp, } /* For unused grid, disable all the pins in the physical_pb_type */ - for (int iblk = 0; iblk < type->capacity; ++iblk) { + for (int iblk = 0; iblk < grid_type->capacity; ++iblk) { /* Bypass used blocks */ if (true == grid_usage[iblk]) { continue; } - print_analysis_sdc_disable_unused_pb_type(fp, type, grid_coordinate, module_manager, iblk, border_side); + print_analysis_sdc_disable_unused_pb_block(fp, grid_type, grid_coordinate, module_manager, grid_instance_name, iblk, border_side); } } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp index e23ec60f9..a05d6abf7 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp @@ -926,7 +926,7 @@ void rec_build_physical_block_modules(ModuleManager& module_manager, /* Add the memory module as a child of primitive module */ module_manager.add_child_module(pb_module, child_pb_module); - /* Set an instance name to bind to a block in bitstream generation */ + /* Set an instance name to bind to a block in bitstream generation and SDC generation! */ std::string child_pb_instance_name = generate_physical_block_instance_name(pb_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild]), inst); module_manager.set_child_instance_name(pb_module, child_pb_module, child_instance_id, child_pb_instance_name); From d84cd662874c59ee884f80752aac9fe1da993702 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 12 Nov 2019 22:18:13 -0700 Subject: [PATCH 64/68] refactored analysis SDC generator for grids --- .../analysis_sdc_grid_writer.cpp | 387 +++++++++++++++++- .../analysis_sdc_routing_writer.cpp | 98 +---- .../backend_assistant/analysis_sdc_writer.cpp | 2 +- .../analysis_sdc_writer_utils.cpp | 235 +++++++++++ .../analysis_sdc_writer_utils.h | 40 ++ .../module_builder/build_grid_modules.cpp | 6 +- 6 files changed, 653 insertions(+), 115 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer_utils.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer_utils.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp index 2a491f129..235e99bee 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp @@ -10,6 +10,8 @@ #include "fpga_x2p_utils.h" #include "fpga_x2p_pbtypes_utils.h" +#include "sdc_writer_utils.h" +#include "analysis_sdc_writer_utils.h" #include "analysis_sdc_grid_writer.h" #include "globals.h" @@ -30,6 +32,9 @@ void rec_print_analysis_sdc_disable_unused_pb_graph_nodes(std::fstream& fp, t_pb_graph_node* physical_pb_graph_node, const e_side& border_side) { t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type; + + /* Validate file stream */ + check_file_handler(fp); /* Disable all the ports of current module (parent_module)! * Hierarchy name already includes the instance name of parent_module @@ -72,23 +77,366 @@ void rec_print_analysis_sdc_disable_unused_pb_graph_nodes(std::fstream& fp, } /******************************************************************** + * Disable an unused pin of a pb_graph_node (parent_module) + *******************************************************************/ +static +void disable_pb_graph_node_unused_pin(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& hierarchy_name, + const t_pb_graph_pin& pb_graph_pin, + t_phy_pb* block_physical_pb) { + /* Validate file stream */ + check_file_handler(fp); + + int rr_node_index = pb_graph_pin.rr_node_index_physical_pb; + + /* Identify if the net has been used or not */ + if (false == is_rr_node_to_be_disable_for_analysis(&(block_physical_pb->rr_graph->rr_node[rr_node_index]))) { + /* Used pin; Nothing to do */ + return; + } + /* Reach here, it means that this pin is not used. Disable timing analysis for the pin */ + /* Find the module port by name */ + std::string module_port_name = generate_pb_type_port_name(pb_graph_pin.port); + ModulePortId module_port = module_manager.find_module_port(parent_module, module_port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(parent_module, module_port)); + BasicPort port_to_disable = module_manager.module_port(parent_module, module_port); + port_to_disable.set_width(pb_graph_pin.pin_number, pb_graph_pin.pin_number); + + fp << "set_disable_timing "; + fp << hierarchy_name; + fp << "/"; + fp << generate_sdc_port(port_to_disable); + fp << std::endl; +} + +/******************************************************************** + * Disable unused input ports and output ports of this pb_graph_node (parent_module) + * This function will iterate over all the input pins, output pins + * of the physical_pb_graph_node, and check if they are mapped + * For unused pins, we will find the port in parent_module + * and then print SDC commands to disable them + *******************************************************************/ +static +void disable_pb_graph_node_unused_pins(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& hierarchy_name, + t_pb_graph_node* physical_pb_graph_node, + t_phy_pb* block_physical_pb) { + + /* Disable unused input pins */ + for (int iport = 0; iport < physical_pb_graph_node->num_input_ports; ++iport) { + for (int ipin = 0; ipin < physical_pb_graph_node->num_input_pins[iport]; ++ipin) { + disable_pb_graph_node_unused_pin(fp, module_manager, parent_module, + hierarchy_name, + physical_pb_graph_node->input_pins[iport][ipin], + block_physical_pb); + } + } + + /* Disable unused output pins */ + for (int iport = 0; iport < physical_pb_graph_node->num_output_ports; ++iport) { + for (int ipin = 0; ipin < physical_pb_graph_node->num_output_pins[iport]; ++ipin) { + disable_pb_graph_node_unused_pin(fp, module_manager, parent_module, + hierarchy_name, + physical_pb_graph_node->output_pins[iport][ipin], + block_physical_pb); + } + } + + /* Disable unused clock pins */ + for (int iport = 0; iport < physical_pb_graph_node->num_clock_ports; ++iport) { + for (int ipin = 0; ipin < physical_pb_graph_node->num_clock_pins[iport]; ++ipin) { + disable_pb_graph_node_unused_pin(fp, module_manager, parent_module, + hierarchy_name, + physical_pb_graph_node->clock_pins[iport][ipin], + block_physical_pb); + } + } +} + +/******************************************************************** + * Disable unused inputs of routing multiplexers of this pb_graph_node + * This function will first cache the nets for each input and output pins + * and store the results in a mux_name-to-net mapping + *******************************************************************/ +static +void disable_pb_graph_node_unused_mux_inputs(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& hierarchy_name, + t_pb_graph_node* physical_pb_graph_node, + t_phy_pb* block_physical_pb, + const e_side& border_side) { + t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type; + + int physical_mode_index = find_pb_type_physical_mode_index(*physical_pb_type); + + std::map mux_instance_to_net_map; + + /* Cache the nets for each input pins of each child pb_graph_node */ + for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) { + for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) { + + t_pb_graph_node* child_pb_graph_node = &(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]); + + /* Cache the nets for input pins of the child pb_graph_node */ + for (int iport = 0; iport < child_pb_graph_node->num_input_ports; ++iport) { + for (int ipin = 0; ipin < child_pb_graph_node->num_input_pins[iport]; ++ipin) { + int rr_node_index = child_pb_graph_node->input_pins[iport][ipin].rr_node_index_physical_pb; + /* Generate the mux name */ + std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, &(child_pb_graph_node->input_pins[iport][ipin]), std::string("")); + /* Cache the net */ + mux_instance_to_net_map[mux_instance_name] = block_physical_pb->rr_graph->rr_node[rr_node_index].vpack_net_num; + } + } + + /* Cache the nets for clock pins of the child pb_graph_node */ + for (int iport = 0; iport < child_pb_graph_node->num_clock_ports; ++iport) { + for (int ipin = 0; ipin < child_pb_graph_node->num_clock_pins[iport]; ++ipin) { + int rr_node_index = child_pb_graph_node->clock_pins[iport][ipin].rr_node_index_physical_pb; + /* Generate the mux name */ + std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, &(child_pb_graph_node->clock_pins[iport][ipin]), std::string("")); + /* Cache the net */ + mux_instance_to_net_map[mux_instance_name] = block_physical_pb->rr_graph->rr_node[rr_node_index].vpack_net_num; + } + } + + } + } + + /* Cache the nets for each output pins of this pb_graph_node */ + for (int iport = 0; iport < physical_pb_graph_node->num_output_ports; ++iport) { + for (int ipin = 0; ipin < physical_pb_graph_node->num_output_pins[iport]; ++ipin) { + int rr_node_index = physical_pb_graph_node->output_pins[iport][ipin].rr_node_index_physical_pb; + /* Generate the mux name */ + std::string mux_instance_name = generate_pb_mux_instance_name(GRID_MUX_INSTANCE_PREFIX, &(physical_pb_graph_node->output_pins[iport][ipin]), std::string("")); + /* Cache the net */ + mux_instance_to_net_map[mux_instance_name] = block_physical_pb->rr_graph->rr_node[rr_node_index].vpack_net_num; + } + } + + /* Now disable unused inputs of routing multiplexers, by tracing from input pins of the parent_module */ + for (int iport = 0; iport < physical_pb_graph_node->num_input_ports; ++iport) { + for (int ipin = 0; ipin < physical_pb_graph_node->num_input_pins[iport]; ++ipin) { + /* Find the module port by name */ + std::string module_port_name = generate_pb_type_port_name(physical_pb_graph_node->input_pins[iport][ipin].port); + ModulePortId module_port = module_manager.find_module_port(parent_module, module_port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(parent_module, module_port)); + + int rr_node_index = physical_pb_graph_node->input_pins[iport][ipin].rr_node_index_physical_pb; + t_rr_node* input_rr_node = &(block_physical_pb->rr_graph->rr_node[rr_node_index]); + + disable_analysis_module_input_pin_net_sinks(fp, module_manager, parent_module, + hierarchy_name, + module_port, ipin, + input_rr_node, + mux_instance_to_net_map); + } + } + + for (int iport = 0; iport < physical_pb_graph_node->num_clock_ports; ++iport) { + for (int ipin = 0; ipin < physical_pb_graph_node->num_clock_pins[iport]; ++ipin) { + /* Find the module port by name */ + std::string module_port_name = generate_pb_type_port_name(physical_pb_graph_node->clock_pins[iport][ipin].port); + ModulePortId module_port = module_manager.find_module_port(parent_module, module_port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(parent_module, module_port)); + + int rr_node_index = physical_pb_graph_node->clock_pins[iport][ipin].rr_node_index_physical_pb; + t_rr_node* input_rr_node = &(block_physical_pb->rr_graph->rr_node[rr_node_index]); + + disable_analysis_module_input_pin_net_sinks(fp, module_manager, parent_module, + hierarchy_name, + module_port, ipin, + input_rr_node, + mux_instance_to_net_map); + } + } + + /* Now disable unused inputs of routing multiplexers, by tracing from output pins of the child_module */ + for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) { + /* Generate the name of the Verilog module for this child */ + std::string child_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side); + std::string child_module_name = generate_physical_block_module_name(child_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild])); + + ModuleId child_module = module_manager.find_module(child_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(child_module)); + + for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) { + + t_pb_graph_node* child_pb_graph_node = &(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]); + + for (int iport = 0; iport < child_pb_graph_node->num_output_ports; ++iport) { + for (int ipin = 0; ipin < child_pb_graph_node->num_output_pins[iport]; ++ipin) { + /* Find the module port by name */ + std::string module_port_name = generate_pb_type_port_name(child_pb_graph_node->output_pins[iport][ipin].port); + ModulePortId module_port = module_manager.find_module_port(child_module, module_port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(child_module, module_port)); + + int rr_node_index = child_pb_graph_node->output_pins[iport][ipin].rr_node_index_physical_pb; + t_rr_node* output_rr_node = &(block_physical_pb->rr_graph->rr_node[rr_node_index]); + + disable_analysis_module_output_pin_net_sinks(fp, module_manager, parent_module, + hierarchy_name, + child_module, inst, + module_port, ipin, + output_rr_node, + mux_instance_to_net_map); + } + } + } + } +} + +/******************************************************************** + * Recursively visit all the pb_types in the hierarchy + * and disable all the unused resources, including: + * 1. input ports + * 2. output ports + * 3. unused inputs of routing multiplexers + * + * As this function is executed in a recursive way. + * To avoid repeated disable timing for ports, during each run of this function, + * only the unused input ports, output ports of the parent module will be disabled. + * In addition, we will cache all the net ids mapped to the input ports of + * child modules, and the net ids mapped to the output ports of parent module. + * As such, we can trace from + * 1. the input ports of parent module to disable unused inputs of routing multiplexer + * which drives the inputs of child modules + * + * Parent_module + * +--------------------------------------------- + * | MUX child_module + * | +-------------+ +-------- + * input_pin0(netA) --->|-------->| Routing |------>| + * input_pin1(netB) --->|----x--->| Multiplexer | netA | + * | +-------------+ | + * | | + * + * 2. the output ports of child module to disable unused inputs of routing multiplexer + * which drives the outputs of parent modules + * + * Case 1: + * parent_module + * --------------------------------------+ + * child_module | + * -------------+ | + * | +-------------+ | + * output_pin0 (netA) |--->| Routing |----->|----> + * output_pin1 (netB) |-x->| Multiplexer | netA | + * | +-------------+ | + * + * Case 2: + * + * Parent_module + * +--------------------------------------------- + * | + * | +--------------------------------------------+ + * | | MUX child_module | + * | | +-------------+ +-----------+ | + * | +--->| Routing |------>| | | + * input_pin0(netA) --->|----x--->| Multiplexer | netA | output_pin|-----+ + * | +-------------+ | | netA + * | | | + * + * + * Note: it is a must to disable all the ports in all the child pb_types! + * This can prohibit timing analyzer to consider any FF-to-FF path or + * combinatinal path inside an unused grid, when finding critical paths!!! + *******************************************************************/ +static +void rec_print_analysis_sdc_disable_pb_graph_node_unused_resources(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& hierarchy_name, + t_pb_graph_node* physical_pb_graph_node, + t_phy_pb* block_physical_pb, + const e_side& border_side) { + t_pb_type* physical_pb_type = physical_pb_graph_node->pb_type; + + /* Disable unused input ports and output ports of this pb_graph_node (parent_module) */ + disable_pb_graph_node_unused_pins(fp, module_manager, parent_module, + hierarchy_name, physical_pb_graph_node, block_physical_pb); + + /* Return if this is the primitive pb_type + * Note: this must return before we disable any unused inputs of routing multiplexer! + * This is due to that primitive pb_type does NOT contain any routing multiplexers inside!!! + */ + if (TRUE == is_primitive_pb_type(physical_pb_type)) { + return; + } + + /* Disable unused inputs of routing multiplexers of this pb_graph_node */ + disable_pb_graph_node_unused_mux_inputs(fp, module_manager, parent_module, + hierarchy_name, physical_pb_graph_node, block_physical_pb, + border_side); + + + int physical_mode_index = find_pb_type_physical_mode_index(*physical_pb_type); + + /* Disable all the ports by iterating over its instance in the parent module */ + for (int ichild = 0; ichild < physical_pb_type->modes[physical_mode_index].num_pb_type_children; ++ichild) { + /* Generate the name of the Verilog module for this child */ + std::string child_module_name_prefix = generate_grid_block_prefix(std::string(GRID_MODULE_NAME_PREFIX), border_side); + std::string child_module_name = generate_physical_block_module_name(child_module_name_prefix, &(physical_pb_type->modes[physical_mode_index].pb_type_children[ichild])); + + ModuleId child_module = module_manager.find_module(child_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(child_module)); + + /* Each child may exist multiple times in the hierarchy*/ + for (int inst = 0; inst < physical_pb_type->modes[physical_mode_index].pb_type_children[ichild].num_pb; ++inst) { + std::string child_instance_name = module_manager.instance_name(parent_module, child_module, module_manager.child_module_instances(parent_module, child_module)[inst]); + /* Must have a valid instance name!!! */ + VTR_ASSERT(false == child_instance_name.empty()); + + std::string updated_hierarchy_name = hierarchy_name + std::string("/") + child_instance_name + std::string("/"); + + rec_print_analysis_sdc_disable_pb_graph_node_unused_resources(fp, module_manager, child_module, hierarchy_name, + &(physical_pb_graph_node->child_pb_graph_nodes[physical_mode_index][ichild][inst]), + block_physical_pb, border_side); + } + } +} + +/******************************************************************** + * This function can work in two differnt modes: + * 1. For partially unused pb blocks + * --------------------------------- + * Disable the timing for only unused resources in a physical block + * We have to walk through pb_graph node, port by port and pin by pin. + * Identify which pins have not been used, and then disable the timing + * for these ports. + * Plus, for input ports, we will trace the routing multiplexers + * and disable the timing for unused inputs. + * + * 2. For fully unused pb_blocks + * ----------------------------- * Disable the timing for a fully unused grid! * This is very straightforward! * Just walk through each pb_type and disable all the ports using wildcards *******************************************************************/ static -void print_analysis_sdc_disable_unused_pb_block(std::fstream& fp, - t_type_ptr grid_type, - const vtr::Point& grid_coordinate, - const ModuleManager& module_manager, - const std::string& grid_instance_name, - const size_t& grid_z, - const e_side& border_side) { +void print_analysis_sdc_disable_pb_block_unused_resources(std::fstream& fp, + t_type_ptr grid_type, + const vtr::Point& grid_coordinate, + const ModuleManager& module_manager, + const std::string& grid_instance_name, + const size_t& grid_z, + const e_side& border_side, + t_phy_pb* block_physical_pb, + const bool& unused_block) { /* Check code: if this is an IO block, the border side MUST be valid */ if (IO_TYPE == grid_type) { VTR_ASSERT(NUM_SIDES != border_side); } + /* If the block is partially unused, we should have a physical pb */ + if (false == unused_block) { + VTR_ASSERT(NULL != block_physical_pb); + } + /* Find an unique name to the pb instance in this grid * Note: this must be consistent with the instance name we used in build_grid_module()!!! */ @@ -102,13 +450,25 @@ void print_analysis_sdc_disable_unused_pb_block(std::fstream& fp, /* Print comments */ fp << "#######################################" << std::endl; - fp << "# Disable Timing for unused grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "][" << grid_z << "]" << std::endl; + + if (true == unused_block) { + fp << "# Disable Timing for unused grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "][" << grid_z << "]" << std::endl; + } else { + VTR_ASSERT_SAFE(false == unused_block); + fp << "# Disable Timing for unused resources in grid[" << grid_coordinate.x() << "][" << grid_coordinate.y() << "][" << grid_z << "]" << std::endl; + } + fp << "#######################################" << std::endl; std::string hierarchy_name = grid_instance_name + std::string("/") + pb_instance_name + std::string("/"); /* Go recursively through the pb_graph hierarchy, and disable all the ports level by level */ - rec_print_analysis_sdc_disable_unused_pb_graph_nodes(fp, module_manager, pb_module, hierarchy_name, grid_type->pb_graph_head, border_side); + if (true == unused_block) { + rec_print_analysis_sdc_disable_unused_pb_graph_nodes(fp, module_manager, pb_module, hierarchy_name, grid_type->pb_graph_head, border_side); + } else { + VTR_ASSERT_SAFE(false == unused_block); + rec_print_analysis_sdc_disable_pb_graph_node_unused_resources(fp, module_manager, pb_module, hierarchy_name, grid_type->pb_graph_head, block_physical_pb, border_side); + } } /******************************************************************** @@ -133,7 +493,7 @@ void print_analysis_sdc_disable_unused_grid(std::fstream& fp, */ if ( (NULL == grid_type) || (EMPTY_TYPE == grid_type) - || (0 == L_grids[grid_coordinate.x()][grid_coordinate.y()].offset) ) { + || (0 < L_grids[grid_coordinate.x()][grid_coordinate.y()].offset) ) { return; } @@ -168,6 +528,8 @@ void print_analysis_sdc_disable_unused_grid(std::fstream& fp, /* TODO: verilog_generate_sdc_disable_one_unused_block(fp, &(L_blocks[blk_id])); */ + t_phy_pb* block_phy_pb = (t_phy_pb*) L_blocks[blk_id].phy_pb; + print_analysis_sdc_disable_pb_block_unused_resources(fp, grid_type, grid_coordinate, module_manager, grid_instance_name, iblk, border_side, block_phy_pb, false); } /* For unused grid, disable all the pins in the physical_pb_type */ @@ -176,7 +538,7 @@ void print_analysis_sdc_disable_unused_grid(std::fstream& fp, if (true == grid_usage[iblk]) { continue; } - print_analysis_sdc_disable_unused_pb_block(fp, grid_type, grid_coordinate, module_manager, grid_instance_name, iblk, border_side); + print_analysis_sdc_disable_pb_block_unused_resources(fp, grid_type, grid_coordinate, module_manager, grid_instance_name, iblk, border_side, NULL, true); } } @@ -207,9 +569,6 @@ void print_analysis_sdc_disable_unused_grids(std::fstream& fp, const std::vector>& L_grids, const std::vector& L_blocks, const ModuleManager& module_manager) { - /* TODO: disable inputs of multiplexers - verilog_generate_sdc_disable_unused_grids_muxs(fp, LL_nx, LL_ny, LL_grid, LL_block); - */ /* Process unused core grids */ for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp index 312696456..0509c08de 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_routing_writer.cpp @@ -14,107 +14,11 @@ #include "fpga_x2p_types.h" #include "sdc_writer_utils.h" +#include "analysis_sdc_writer_utils.h" #include "analysis_sdc_routing_writer.h" #include "globals.h" -/******************************************************************** - * Identify if a node should be disabled during analysis SDC generation - *******************************************************************/ -static -bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node) { - /* Conditions to enable timing analysis for a node - * 1st condition: it have a valid vpack_net_number - * 2nd condition: it is not an parasitic net - * 3rd condition: it is not a global net - */ - if ( (OPEN != cur_rr_node->vpack_net_num) - && (FALSE == cur_rr_node->is_parasitic_net) - && (FALSE == vpack_net[cur_rr_node->vpack_net_num].is_global) - && (FALSE == vpack_net[cur_rr_node->vpack_net_num].is_const_gen) ){ - return false; - } - return true; -} - -/******************************************************************** - * Disable all the unused inputs of routing multiplexers, which are not used by benchmark - * Here, we start from each input of a routing module, and traverse forward to the sink - * port of the module net whose source is the input - * We will find the instance name which is the parent of the sink port, and search the - * net id through the instance_name_to_net_map - * The the net id does not match the net id of this input, we will disable the sink port! - * - * parent_module - * +----------------------- - * | MUX instance A - * | +----------- - * input_port--->|--+---x-->| sink port (disable! net_id = Y) - * (net_id = X) | | +---------- - * | | MUX instance B - * | | +---------- - * | +------>| sink port (do not disable! net_id = X) - * - *******************************************************************/ -static -void disable_analysis_module_input_port_net_sinks(std::fstream& fp, - const ModuleManager& module_manager, - const ModuleId& parent_module, - const std::string& parent_instance_name, - const ModulePortId& module_input_port, - t_rr_node* input_rr_node, - const std::map mux_instance_to_net_map) { - /* Validate file stream */ - check_file_handler(fp); - - /* Find the module net which sources from this port! */ - for (const size_t& pin : module_manager.module_port(parent_module, module_input_port).pins()) { - ModuleNetId module_net = module_manager.module_instance_port_net(parent_module, parent_module, 0, module_input_port, pin); - VTR_ASSERT(true == module_manager.valid_module_net_id(parent_module, module_net)); - - /* Touch each sink of the net! */ - for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(parent_module, module_net)) { - ModuleId sink_module = module_manager.net_sink_modules(parent_module, module_net)[sink_id]; - size_t sink_instance = module_manager.net_sink_instances(parent_module, module_net)[sink_id]; - - /* Skip when sink module is the parent module, - * the output ports of parent modules have been disabled/enabled already! - */ - if (sink_module == parent_module) { - continue; - } - - std::string sink_instance_name = module_manager.instance_name(parent_module, sink_module, sink_instance); - bool disable_timing = false; - /* Check if this node is used by benchmark */ - if (true == is_rr_node_to_be_disable_for_analysis(input_rr_node)) { - /* Disable all the sinks! */ - disable_timing = true; - } else { - /* See if the net id matches. If does not match, we should disable! */ - if (input_rr_node->vpack_net_num != mux_instance_to_net_map.at(sink_instance_name)) { - disable_timing = true; - } - } - - /* Time to write SDC command to disable timing or not */ - if (false == disable_timing) { - continue; - } - - BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(parent_module, module_net)[sink_id]); - sink_port.set_width(module_manager.net_sink_pins(parent_module, module_net)[sink_id], - module_manager.net_sink_pins(parent_module, module_net)[sink_id]); - /* Get the input id that is used! Disable the unused inputs! */ - fp << "set_disable_timing "; - fp << parent_instance_name << "/"; - fp << sink_instance_name << "/"; - fp << generate_sdc_port(sink_port); - fp << std::endl; - } - } -} - /******************************************************************** * This function will disable * 1. all the unused port (unmapped by a benchmark) of a connection block diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp index 8aed25fc0..d4297d8dc 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer.cpp @@ -255,7 +255,7 @@ void print_analysis_sdc(const std::string& sdc_dir, L_device_rr_gsb, compact_routing_hierarchy); - /* TODO: Disable timing for unused routing resources in grids (programmable blocks) */ + /* Disable timing for unused routing resources in grids (programmable blocks) */ print_analysis_sdc_disable_unused_grids(fp, device_size, L_grids, L_blocks, module_manager); /* Close file handler */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer_utils.cpp new file mode 100644 index 000000000..3c2885fd3 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer_utils.cpp @@ -0,0 +1,235 @@ +/******************************************************************** + * This file includes most utilized functions + * that are used to output a SDC file + * in order to constrain a FPGA fabric (P&Red netlist) mapped to a benchmark + *******************************************************************/ +#include "vtr_assert.h" + +#include "fpga_x2p_utils.h" + +#include "sdc_writer_utils.h" +#include "analysis_sdc_writer_utils.h" + +#include "globals.h" + +/******************************************************************** + * Identify if a node should be disabled during analysis SDC generation + *******************************************************************/ +bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node) { + /* Conditions to enable timing analysis for a node + * 1st condition: it have a valid vpack_net_number + * 2nd condition: it is not an parasitic net + * 3rd condition: it is not a global net + */ + if ( (OPEN != cur_rr_node->vpack_net_num) + && (FALSE == cur_rr_node->is_parasitic_net) + && (FALSE == vpack_net[cur_rr_node->vpack_net_num].is_global) + && (FALSE == vpack_net[cur_rr_node->vpack_net_num].is_const_gen) ){ + return false; + } + return true; +} + +/******************************************************************** + * Disable all the unused inputs of routing multiplexers, which are not used by benchmark + * Here, we start from each input of a routing module, and traverse forward to the sink + * port of the module net whose source is the input + * We will find the instance name which is the parent of the sink port, and search the + * net id through the instance_name_to_net_map + * The the net id does not match the net id of this input, we will disable the sink port! + * + * parent_module + * +----------------------- + * | MUX instance A + * | +----------- + * input_port--->|--+---x-->| sink port (disable! net_id = Y) + * (net_id = X) | | +---------- + * | | MUX instance B + * | | +---------- + * | +------>| sink port (do not disable! net_id = X) + * + *******************************************************************/ +void disable_analysis_module_input_pin_net_sinks(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& parent_instance_name, + const ModulePortId& module_input_port, + const size_t& module_input_pin, + t_rr_node* input_rr_node, + const std::map mux_instance_to_net_map) { + /* Validate file stream */ + check_file_handler(fp); + + /* Find the module net which sources from this port! */ + ModuleNetId module_net = module_manager.module_instance_port_net(parent_module, parent_module, 0, module_input_port, module_input_pin); + VTR_ASSERT(true == module_manager.valid_module_net_id(parent_module, module_net)); + + /* Touch each sink of the net! */ + for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(parent_module, module_net)) { + ModuleId sink_module = module_manager.net_sink_modules(parent_module, module_net)[sink_id]; + size_t sink_instance = module_manager.net_sink_instances(parent_module, module_net)[sink_id]; + + /* Skip when sink module is the parent module, + * the output ports of parent modules have been disabled/enabled already! + */ + if (sink_module == parent_module) { + continue; + } + + std::string sink_instance_name = module_manager.instance_name(parent_module, sink_module, sink_instance); + bool disable_timing = false; + /* Check if this node is used by benchmark */ + if (true == is_rr_node_to_be_disable_for_analysis(input_rr_node)) { + /* Disable all the sinks! */ + disable_timing = true; + } else { + std::map::const_iterator it = mux_instance_to_net_map.find(sink_instance_name); + if (it != mux_instance_to_net_map.end()) { + /* See if the net id matches. If does not match, we should disable! */ + if (input_rr_node->vpack_net_num != mux_instance_to_net_map.at(sink_instance_name)) { + disable_timing = true; + } + } + } + + /* Time to write SDC command to disable timing or not */ + if (false == disable_timing) { + continue; + } + + BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(parent_module, module_net)[sink_id]); + sink_port.set_width(module_manager.net_sink_pins(parent_module, module_net)[sink_id], + module_manager.net_sink_pins(parent_module, module_net)[sink_id]); + /* Get the input id that is used! Disable the unused inputs! */ + fp << "set_disable_timing "; + fp << parent_instance_name << "/"; + fp << sink_instance_name << "/"; + fp << generate_sdc_port(sink_port); + fp << std::endl; + } +} + + +/******************************************************************** + * Disable all the unused inputs of routing multiplexers, which are not used by benchmark + * Here, we start from each input of a routing module, and traverse forward to the sink + * port of the module net whose source is the input + * We will find the instance name which is the parent of the sink port, and search the + * net id through the instance_name_to_net_map + * The the net id does not match the net id of this input, we will disable the sink port! + * + * parent_module + * +----------------------- + * | MUX instance A + * | +----------- + * input_port--->|--+---x-->| sink port (disable! net_id = Y) + * (net_id = X) | | +---------- + * | | MUX instance B + * | | +---------- + * | +------>| sink port (do not disable! net_id = X) + * + *******************************************************************/ +void disable_analysis_module_input_port_net_sinks(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& parent_instance_name, + const ModulePortId& module_input_port, + t_rr_node* input_rr_node, + const std::map mux_instance_to_net_map) { + /* Validate file stream */ + check_file_handler(fp); + + /* Find the module net which sources from this port! */ + for (const size_t& pin : module_manager.module_port(parent_module, module_input_port).pins()) { + disable_analysis_module_input_pin_net_sinks(fp, module_manager, parent_module, + parent_instance_name, + module_input_port, pin, + input_rr_node, + mux_instance_to_net_map); + } +} + +/******************************************************************** + * Disable all the unused inputs of routing multiplexers, which are not used by benchmark + * Here, we start from each output of a child module, and traverse forward to the sink + * port of the module net whose source is the input + * We will find the instance name which is the parent of the sink port, and search the + * net id through the instance_name_to_net_map + * The the net id does not match the net id of this input, we will disable the sink port! + * + * Parent_module + * +--------------------------------------------- + * | + * | +--------------------------------------------+ + * | | MUX child_module | + * | | +-------------+ +-----------+ | + * | +--->| Routing |------>| | | + * input_pin0(netA) --->|----x--->| Multiplexer | netA | output_pin|-----+ + * | +-------------+ | | netA + * | | | + * + + * + *******************************************************************/ +void disable_analysis_module_output_pin_net_sinks(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& parent_instance_name, + const ModuleId& child_module, + const size_t& child_instance, + const ModulePortId& child_module_port, + const size_t& child_module_pin, + t_rr_node* output_rr_node, + const std::map mux_instance_to_net_map) { + /* Validate file stream */ + check_file_handler(fp); + + /* Find the module net which sources from this port! */ + ModuleNetId module_net = module_manager.module_instance_port_net(parent_module, child_module, child_instance, child_module_port, child_module_pin); + VTR_ASSERT(true == module_manager.valid_module_net_id(parent_module, module_net)); + + /* Touch each sink of the net! */ + for (const ModuleNetSinkId& sink_id : module_manager.module_net_sinks(parent_module, module_net)) { + ModuleId sink_module = module_manager.net_sink_modules(parent_module, module_net)[sink_id]; + size_t sink_instance = module_manager.net_sink_instances(parent_module, module_net)[sink_id]; + + /* Skip when sink module is the parent module, + * the output ports of parent modules have been disabled/enabled already! + */ + if (sink_module == parent_module) { + continue; + } + + std::string sink_instance_name = module_manager.instance_name(parent_module, sink_module, sink_instance); + bool disable_timing = false; + /* Check if this node is used by benchmark */ + if (true == is_rr_node_to_be_disable_for_analysis(output_rr_node)) { + /* Disable all the sinks! */ + disable_timing = true; + } else { + std::map::const_iterator it = mux_instance_to_net_map.find(sink_instance_name); + if (it != mux_instance_to_net_map.end()) { + /* See if the net id matches. If does not match, we should disable! */ + if (output_rr_node->vpack_net_num != mux_instance_to_net_map.at(sink_instance_name)) { + disable_timing = true; + } + } + } + + /* Time to write SDC command to disable timing or not */ + if (false == disable_timing) { + continue; + } + + BasicPort sink_port = module_manager.module_port(sink_module, module_manager.net_sink_ports(parent_module, module_net)[sink_id]); + sink_port.set_width(module_manager.net_sink_pins(parent_module, module_net)[sink_id], + module_manager.net_sink_pins(parent_module, module_net)[sink_id]); + /* Get the input id that is used! Disable the unused inputs! */ + fp << "set_disable_timing "; + fp << parent_instance_name << "/"; + fp << sink_instance_name << "/"; + fp << generate_sdc_port(sink_port); + fp << std::endl; + } +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer_utils.h new file mode 100644 index 000000000..7b5ff9348 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_writer_utils.h @@ -0,0 +1,40 @@ +#ifndef ANALYSIS_SDC_WRITER_UTILS_H +#define ANALYSIS_SDC_WRITER_UTILS_H + +#include +#include +#include +#include "module_manager.h" +#include "vpr_types.h" + +bool is_rr_node_to_be_disable_for_analysis(t_rr_node* cur_rr_node); + +void disable_analysis_module_input_pin_net_sinks(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& parent_instance_name, + const ModulePortId& module_input_port, + const size_t& module_input_pin, + t_rr_node* input_rr_node, + const std::map mux_instance_to_net_map); + +void disable_analysis_module_input_port_net_sinks(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& parent_instance_name, + const ModulePortId& module_input_port, + t_rr_node* input_rr_node, + const std::map mux_instance_to_net_map) ; + +void disable_analysis_module_output_pin_net_sinks(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const std::string& parent_instance_name, + const ModuleId& child_module, + const size_t& child_instance, + const ModulePortId& child_module_port, + const size_t& child_module_pin, + t_rr_node* output_rr_node, + const std::map mux_instance_to_net_map); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp index a05d6abf7..f6a940d85 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_grid_modules.cpp @@ -483,7 +483,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager, } /* Initialize the interconnection type that will be physically implemented in module */ - enum e_interconnect verilog_interc_type = determine_actual_pb_interc_type(cur_interc, fan_in); + enum e_interconnect interc_type = determine_actual_pb_interc_type(cur_interc, fan_in); /* Find input ports of the wire module */ std::vector interc_model_inputs = circuit_lib.model_ports_by_type(cur_interc->circuit_model, SPICE_MODEL_PORT_INPUT, true); /* the last argument to guarantee that we ignore any global inputs */ @@ -497,7 +497,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager, /* Branch on the type of physical implementation, * We add instances of programmable interconnection */ - switch (verilog_interc_type) { + switch (interc_type) { case DIRECT_INTERC: { /* Ensure direct interc has only one fan-in */ VTR_ASSERT(1 == fan_in); @@ -521,7 +521,7 @@ void add_module_pb_graph_pin_interc(ModuleManager& module_manager, /* Get the instance id and add an instance of wire */ size_t wire_instance = module_manager.num_instance(pb_module, wire_module); module_manager.add_child_module(pb_module, wire_module); - + /* Ensure input and output ports of the wire model has only 1 pin respectively */ VTR_ASSERT(1 == circuit_lib.port_size(interc_model_inputs[0])); VTR_ASSERT(1 == circuit_lib.port_size(interc_model_outputs[0])); From 1291b99d66b95309538941e9f1c7079403d85a5b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 13 Nov 2019 12:55:57 -0700 Subject: [PATCH 65/68] now make ini file generation more flexible: user can specify a name or use the default name --- vpr7_x2p/vpr/SRC/base/OptionTokens.c | 1 + vpr7_x2p/vpr/SRC/base/OptionTokens.h | 1 + vpr7_x2p/vpr/SRC/base/ReadOptions.c | 2 + vpr7_x2p/vpr/SRC/base/SetupVPR.c | 6 ++- vpr7_x2p/vpr/SRC/base/vpr_api.c | 3 +- .../verilog/simulation_info_writer.cpp | 41 ++++++++++++++----- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 6 ++- 7 files changed, 47 insertions(+), 13 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/base/OptionTokens.c b/vpr7_x2p/vpr/SRC/base/OptionTokens.c index cdf5eef91..b8ef5c44a 100644 --- a/vpr7_x2p/vpr/SRC/base/OptionTokens.c +++ b/vpr7_x2p/vpr/SRC/base/OptionTokens.c @@ -101,6 +101,7 @@ struct s_TokenPair OptionBaseTokenList[] = { { "fpga_verilog_print_sdc_pnr", OT_FPGA_VERILOG_SYN_PRINT_SDC_PNR }, /* Specify the simulator path for Verilog netlists */ { "fpga_verilog_print_sdc_analysis", OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS }, /* Specify the simulator path for Verilog netlists */ { "fpga_verilog_print_simulation_ini", OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI }, /* Specify the simulator path for Verilog netlists */ + { "fpga_verilog_simulation_ini_file", OT_FPGA_VERILOG_SYN_SIMULATION_INI_FILE }, /* Specify the simulator path for Verilog netlists */ /* Xifan Tang: Bitstream generator */ { "fpga_bitstream_generator", OT_FPGA_BITSTREAM_GENERATOR }, /* turn on bitstream generator, and specify the output file */ // { "fpga_bitstream_output_file", OT_FPGA_BITSTREAM_OUTPUT_FILE }, /* turn on bitstream generator, and specify the output file */ // AA: temporarily deprecated diff --git a/vpr7_x2p/vpr/SRC/base/OptionTokens.h b/vpr7_x2p/vpr/SRC/base/OptionTokens.h index 706a81b24..5b20ef1cd 100644 --- a/vpr7_x2p/vpr/SRC/base/OptionTokens.h +++ b/vpr7_x2p/vpr/SRC/base/OptionTokens.h @@ -118,6 +118,7 @@ enum e_OptionBaseToken { OT_FPGA_VERILOG_SYN_PRINT_SDC_PNR, OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS, OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI, + OT_FPGA_VERILOG_SYN_SIMULATION_INI_FILE, /* Xifan Tang: Bitstream generator */ OT_FPGA_BITSTREAM_GENERATOR, OT_FPGA_BITSTREAM_OUTPUT_FILE, diff --git a/vpr7_x2p/vpr/SRC/base/ReadOptions.c b/vpr7_x2p/vpr/SRC/base/ReadOptions.c index d2f692774..e51dcf530 100644 --- a/vpr7_x2p/vpr/SRC/base/ReadOptions.c +++ b/vpr7_x2p/vpr/SRC/base/ReadOptions.c @@ -560,6 +560,8 @@ ProcessOption(INP char **Args, INOUTP t_options * Options) { case OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS: return Args; case OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI: + return Args; + case OT_FPGA_VERILOG_SYN_SIMULATION_INI_FILE: return ReadString(Args, &Options->fpga_verilog_simulation_ini_path); /* Xifan TANG: Bitstream generator */ case OT_FPGA_BITSTREAM_GENERATOR: diff --git a/vpr7_x2p/vpr/SRC/base/SetupVPR.c b/vpr7_x2p/vpr/SRC/base/SetupVPR.c index 56ec465d2..f1443c4f7 100644 --- a/vpr7_x2p/vpr/SRC/base/SetupVPR.c +++ b/vpr7_x2p/vpr/SRC/base/SetupVPR.c @@ -1114,6 +1114,7 @@ static void SetupSynVerilogOpts(t_options Options, syn_verilog_opts->print_sdc_analysis = FALSE; syn_verilog_opts->include_icarus_simulator = FALSE; syn_verilog_opts->print_simulation_ini = FALSE; + syn_verilog_opts->simulation_ini_path = NULL; /* Turn on Syn_verilog options */ if (Options.Count[OT_FPGA_VERILOG_SYN]) { @@ -1186,7 +1187,10 @@ static void SetupSynVerilogOpts(t_options Options, if (Options.Count[OT_FPGA_VERILOG_SYN_PRINT_SIMULATION_INI]) { syn_verilog_opts->print_simulation_ini = TRUE; - syn_verilog_opts->simulation_ini_path = my_strdup(Options.fpga_verilog_simulation_ini_path); + + if (Options.Count[OT_FPGA_VERILOG_SYN_SIMULATION_INI_FILE]) { + syn_verilog_opts->simulation_ini_path = my_strdup(Options.fpga_verilog_simulation_ini_path); + } } /* SynVerilog needs the input from spice modeling */ diff --git a/vpr7_x2p/vpr/SRC/base/vpr_api.c b/vpr7_x2p/vpr/SRC/base/vpr_api.c index 552a90b36..3b2471a72 100644 --- a/vpr7_x2p/vpr/SRC/base/vpr_api.c +++ b/vpr7_x2p/vpr/SRC/base/vpr_api.c @@ -211,7 +211,8 @@ void vpr_print_usage(void) { vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_report_timing_rpt_path \n"); vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_sdc_pnr\n"); vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_sdc_analysis\n"); - vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_simulation_ini \n"); + vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_print_simulation_ini\n"); + vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_verilog_simulation_ini_file \n"); /* Xifan Tang: Bitstream generator */ vpr_printf(TIO_MESSAGE_INFO, "Bitstream Generator Options:\n"); vpr_printf(TIO_MESSAGE_INFO, "\t--fpga_bitstream_generator\n"); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp index aa59a003b..e2b347f84 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/simulation_info_writer.cpp @@ -2,8 +2,8 @@ * This function includes the writer for generating exchangeable * information, in order to interface different simulators ********************************************************************/ -#include -#include +#include +#include #include #define MINI_CASE_SENSITIVE #include "ini.h" @@ -18,6 +18,11 @@ #include "verilog_global.h" #include "simulation_info_writer.h" +/********************************************************************* + * Local Variable + ********************************************************************/ +constexpr char* DEFAULT_SIMULATION_INI_FILE_NAME = "simulation_deck_info.ini"; + /********************************************************************* * Top-level function to write an ini file which contains exchangeable * information, in order to interface different Verilog simulators @@ -30,6 +35,22 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, const int& num_operating_clock_cycles, const float& prog_clock_freq, const float& op_clock_freq) { + + /* Start time count */ + clock_t t_start = clock(); + + /* Use default name if user does not provide one */ + std::string ini_fname; + if (true == simulation_ini_filename.empty()) { + ini_fname = parent_dir + std::string(DEFAULT_SIMULATION_INI_FILE_NAME); + } else { + ini_fname = simulation_ini_filename; + } + + vpr_printf(TIO_MESSAGE_INFO, + "Writing exchangeable file containing simulation information: %s...", + ini_fname.c_str()); + mINI::INIStructure ini; // std::map units_map; // units_map['s']=1; // units_map['ms']=1E-3; // units_map['us']=1E-6; @@ -50,14 +71,14 @@ void print_verilog_simulation_info(const std::string& simulation_ini_filename, ini["SIMULATION_DECK"]["VERILOG_FILE1"] = std::string(defines_verilog_file_name); ini["SIMULATION_DECK"]["VERILOG_FILE2"] = std::string(circuit_name + "_include_netlists.v"); - /* Use default name if user does not provide one */ - std::string ini_fname; - if (true == simulation_ini_filename.empty()) { - ini_fname = parent_dir + std::string("SimulationDeckInfo.ini"); - } else { - ini_fname = simulation_ini_filename; - } - mINI::INIFile file(ini_fname); file.generate(ini, true); + + /* 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); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index a92e8b598..57e742fe7 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -438,7 +438,11 @@ void vpr_fpga_verilog(ModuleManager& module_manager, if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_simulation_ini) { /* Print exchangeable files which contains simulation settings */ - print_verilog_simulation_info(std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path), + std::string simulation_ini_file_name; + if (NULL != vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path) { + simulation_ini_file_name = std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.simulation_ini_path); + } + print_verilog_simulation_info(simulation_ini_file_name, std::string(format_dir_path(chomped_parent_dir)), std::string(chomped_circuit_name), std::string(src_dir_path), From 0c2ad5ab5e1c5317ae166d2e1f07edc46c0700dc Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 13 Nov 2019 20:45:41 -0700 Subject: [PATCH 66/68] critical bug fixed for some corner cases --- .../backend_assistant/analysis_sdc_grid_writer.cpp | 5 +++++ .../backend_assistant/pnr_sdc_routing_writer.cpp | 10 ++++++++++ .../fpga_x2p/module_builder/build_routing_modules.cpp | 2 +- vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c | 6 +++++- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp index 235e99bee..9eac8c52a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/analysis_sdc_grid_writer.cpp @@ -278,6 +278,11 @@ void disable_pb_graph_node_unused_mux_inputs(std::fstream& fp, int rr_node_index = child_pb_graph_node->output_pins[iport][ipin].rr_node_index_physical_pb; t_rr_node* output_rr_node = &(block_physical_pb->rr_graph->rr_node[rr_node_index]); + /* Corner case: if the rr node has no fan-out we will skip this pin */ + if (0 == output_rr_node->num_edges) { + continue; + } + disable_analysis_module_output_pin_net_sinks(fp, module_manager, parent_module, hierarchy_name, child_module, inst, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp index 13bc17d1c..1efc9279c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/backend_assistant/pnr_sdc_routing_writer.cpp @@ -237,6 +237,15 @@ void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp, check_file_handler(fp); VTR_ASSERT(IPIN == output_rr_node->type); + + /* We have OPINs since we may have direct connections: + * These connections should be handled by other functions in the compact_netlist.c + * So we just return here for OPINs + */ + if ( (1 == output_rr_node->num_drive_rr_nodes) + && (OPIN == output_rr_node->drive_rr_nodes[0]->type) ) { + return; + } /* Find the module port corresponding to the output rr_node */ ModulePortId module_output_port = find_connection_block_module_ipin_port(module_manager, @@ -247,6 +256,7 @@ void print_pnr_sdc_constrain_cb_mux_timing(std::fstream& fp, /* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */ std::vector input_rr_nodes; for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) { + /* Skip OPINs which should be handled in direct connection */ input_rr_nodes.push_back(output_rr_node->drive_rr_nodes[iedge]); } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp index b43baa0f4..fcd0f93d2 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_routing_modules.cpp @@ -446,7 +446,7 @@ void build_connection_block_module_short_interc(ModuleManager& module_manager, /* Ensure we have only one 1 driver node */ VTR_ASSERT_SAFE(1 == src_rr_node->fan_in); - /* Find the driver node */ + /* Find the driver node */ t_rr_node* drive_rr_node = src_rr_node->drive_rr_nodes[0]; /* We have OPINs since we may have direct connections: diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 57e742fe7..9047cb473 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -515,9 +515,13 @@ void vpr_fpga_verilog(ModuleManager& module_manager, } /* Print a Verilog file including all the netlists that have been generated */ + std::string ref_verilog_benchmark_file_name; + if (NULL != vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file) { + ref_verilog_benchmark_file_name = std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file); + } print_include_netlists(std::string(src_dir_path), std::string(chomped_circuit_name), - std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file), + ref_verilog_benchmark_file_name, Arch.spice->circuit_lib); vpr_printf(TIO_MESSAGE_INFO, "Outputted %lu Verilog modules in total.\n", module_manager.num_modules()); From 4df6402241081be24bec92c7a0d09dc8d735ffc5 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 15 Nov 2019 14:23:03 -0700 Subject: [PATCH 67/68] add python script for batch simulations --- openfpga_flow/scripts/run_simulation_task.py | 71 +++++++++++++++++++ .../tasks/single_mode/config/task.conf | 1 + 2 files changed, 72 insertions(+) create mode 100644 openfpga_flow/scripts/run_simulation_task.py diff --git a/openfpga_flow/scripts/run_simulation_task.py b/openfpga_flow/scripts/run_simulation_task.py new file mode 100644 index 000000000..ad1e5f863 --- /dev/null +++ b/openfpga_flow/scripts/run_simulation_task.py @@ -0,0 +1,71 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Script Name : regression.py +# Description : This script designed to run: +# openfpga_flow tasks +# run_{simulator}.py +# Args : python3 regression.py --help +# Author : Aurelien Alacchi +# Email : aurelien.alacchi@utah.edu +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +import os +import sys +import shutil +import time +from datetime import timedelta +import shlex +import argparse +from configparser import ConfigParser, ExtendedInterpolation +import logging +import glob +import subprocess +import threading +import csv +from string import Template +import pprint +from importlib import util +from collections import OrderedDict + +modelsim="modelsim" +vcs="vcs" +formality="formality" +modelsim_file="simulation_deck_info.ini" +ini_list="" + +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Parse commandline arguments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +parser = argparse.ArgumentParser() +parser.add_argument('tasks', nargs='+') +parser.add_argument('--maxthreads', type=int, default=2, + help="Number of fpga_flow threads to run default = 2," + + "Typically <= Number of processors on the system") +parser.add_argument('--simulator', type=str, default=modelsim, + help="Simulator to use. Set at \"" + modelsim + "\" by default. Can also be \"" + vcs + "\" or \"" + formality + "\"") +args = parser.parse_args() + + +args.tasks=str(args.tasks).strip('[]') +#print(args.tasks) +#print(args.maxthreads) + +command="python3 openfpga_flow/scripts/run_fpga_task.py " + args.tasks + " --maxthreads " + str(args.maxthreads) + " --debug --show_thread_logs" + +print(command) + +os.system(command) + +if(args.simulator == modelsim): + command="python3 openfpga_flow/scripts/run_modelsim.py" + os.system("grep \"INFO - Run directory :\" openfpga_flow/tasks/" + args.tasks + "/latest/*.log > paths_ini.txt") + arguments = " --skip_prompt --run_sim"; + fp = open("paths_ini.txt") + line = fp.readline() + while line: + ini_list= ini_list + line + modelsim_file + line = fp.readline() + ini_list = ini_list.replace("INFO - Run directory :", "") + ini_list = ini_list.replace("\n", "/") + fp.close() + print(command + ini_list + arguments) + os.system(command + ini_list + arguments) diff --git a/openfpga_flow/tasks/single_mode/config/task.conf b/openfpga_flow/tasks/single_mode/config/task.conf index 4d721002b..e3e2d3e8c 100644 --- a/openfpga_flow/tasks/single_mode/config/task.conf +++ b/openfpga_flow/tasks/single_mode/config/task.conf @@ -55,4 +55,5 @@ vpr_fpga_verilog_print_sdc_pnr= vpr_fpga_verilog_print_sdc_analysis= vpr_fpga_verilog_explicit_mapping= vpr_fpga_x2p_compact_routing_hierarchy= +#vpr_fpga_verilog_print_simulation_ini= end_flow_with_test= From f52eaef622175403f761aad6c872a3552b9947da Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Fri, 15 Nov 2019 14:35:15 -0700 Subject: [PATCH 68/68] Updated flow script and skipped travis upload on failure test setup. --- openfpga_flow/scripts/run_fpga_flow.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openfpga_flow/scripts/run_fpga_flow.py b/openfpga_flow/scripts/run_fpga_flow.py index 06a52e6d7..04634071f 100644 --- a/openfpga_flow/scripts/run_fpga_flow.py +++ b/openfpga_flow/scripts/run_fpga_flow.py @@ -191,9 +191,8 @@ VeriPar.add_argument('--vpr_fpga_verilog_print_top_tb', action="store_true", VeriPar.add_argument('--vpr_fpga_verilog_print_input_blif_tb', action="store_true", help="Print testbench" + "for input blif file in Verilog Generator") -VeriPar.add_argument('--vpr_fpga_verilog_print_modelsim_autodeck', type=str, - help="Print modelsim " + - "simulation script", metavar="") +VeriPar.add_argument('--vpr_fpga_verilog_print_simulation_ini', action="store_true", + help="Create simulation INI file") VeriPar.add_argument('--vpr_fpga_verilog_explicit_mapping', action="store_true", help="Explicit Mapping") @@ -721,9 +720,8 @@ def run_standard_vpr(bench_blif, fixed_chan_width, logfile, route_only=False): command += ["--fpga_verilog_include_signal_init"] if args.vpr_fpga_verilog_formal_verification_top_netlist: command += ["--fpga_verilog_print_formal_verification_top_netlist"] - if args.vpr_fpga_verilog_print_modelsim_autodeck: - command += ["--fpga_verilog_print_modelsim_autodeck", - args.vpr_fpga_verilog_print_modelsim_autodeck] + if args.vpr_fpga_verilog_print_simulation_ini: + command += ["--fpga_verilog_print_simulation_ini"] if args.vpr_fpga_verilog_include_icarus_simulator: command += ["--fpga_verilog_include_icarus_simulator"] if args.vpr_fpga_verilog_print_report_timing_tcl: