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