diff --git a/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.cpp index a509343d0..a14007fe4 100644 --- a/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.cpp @@ -65,9 +65,11 @@ void print_verilog_top_random_testbench_ports(std::fstream& fp, /* Create a clock port if the benchmark does not have one! * The clock is used for counting and synchronizing input stimulus */ - BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME)); + std::vector clock_ports = 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; + for (const BasicPort& clock_port : clock_ports) { + fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, clock_port) << ";" << std::endl; + } /* Add an empty line as splitter */ fp << std::endl; @@ -227,16 +229,16 @@ void print_verilog_random_top_testbench(const std::string& circuit_name, explicit_port_mapping); /* Find clock port to be used */ - BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME)); + std::vector clock_ports = 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_clock_stimuli(fp, simulation_parameters, - clock_port); + clock_ports); print_verilog_testbench_random_stimuli(fp, atom_ctx, netlist_annotation, clock_port_names, std::string(CHECKFLAG_PORT_POSTFIX), - clock_port); + clock_ports); print_verilog_testbench_check(fp, std::string(AUTOCHECKED_SIMULATION_FLAG), diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp index 7be3bfd10..9587e5960 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp @@ -347,14 +347,18 @@ void print_verilog_timeout_and_vcd(std::fstream& fp, * 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) { +std::vector generate_verilog_testbench_clock_port(const std::vector& clock_port_names, + const std::string& default_clock_name) { + std::vector clock_ports; if (0 == clock_port_names.size()) { - return BasicPort(default_clock_name, 1); + clock_ports.push_back(BasicPort(default_clock_name, 1)); + } else { + for (const std::string& clock_port_name : clock_port_names) { + clock_ports.push_back(BasicPort(clock_port_name, 1)); + } } - VTR_ASSERT(1 == clock_port_names.size()); - return BasicPort(clock_port_names[0], 1); + return clock_ports; } /******************************************************************** @@ -382,7 +386,7 @@ void print_verilog_testbench_check(std::fstream& fp, print_verilog_comment(fp, std::string("----- Begin checking output vectors -------")); - BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, default_clock_name); + std::vector clock_ports = 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 -------")); @@ -391,7 +395,14 @@ void print_verilog_testbench_check(std::fstream& fp, 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; + /* TODO: This is limitation when multiple clock signals exist + * Ideally, all the input signals are generated by different clock edges, + * depending which clock domain the signals belong to + * Currently, as we lack the information, we only use the first clock signal + */ + VTR_ASSERT(1 <= clock_ports.size()); + + fp << "\talways@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_ports[0]) << ") 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); @@ -466,27 +477,29 @@ void print_verilog_testbench_check(std::fstream& fp, *******************************************************************/ void print_verilog_testbench_clock_stimuli(std::fstream& fp, const SimulationSetting& simulation_parameters, - const BasicPort& clock_port) { + const std::vector& clock_ports) { /* Validate the file stream */ valid_file_stream(fp); - print_verilog_comment(fp, std::string("----- Clock Initialization -------")); + for (const BasicPort& clock_port : clock_ports) { + print_verilog_comment(fp, std::string("----- Clock '") + clock_port.get_name() + std::string("' Initialization -------")); - fp << "\tinitial begin" << std::endl; - /* Create clock stimuli */ - 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(10) << ((0.5/simulation_parameters.operating_clock_frequency())/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 << "\tinitial begin" << std::endl; + /* Create clock stimuli */ + 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(10) << ((0.5/simulation_parameters.operating_clock_frequency())/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; + fp << "\tend" << std::endl; - /* Add an empty line as splitter */ - fp << std::endl; + /* Add an empty line as splitter */ + fp << std::endl; + } } /******************************************************************** @@ -498,7 +511,7 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp, const VprNetlistAnnotation& netlist_annotation, const std::vector& clock_port_names, const std::string& check_flag_port_postfix, - const BasicPort& clock_port) { + const std::vector& clock_ports) { /* Validate the file stream */ valid_file_stream(fp); @@ -557,25 +570,14 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp, /* 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; + /* TODO: This is limitation when multiple clock signals exist + * Ideally, all the input signals are generated by different clock edges, + * depending which clock domain the signals belong to + * Currently, as we lack the information, we only use the first clock signal + */ + VTR_ASSERT(1 <= clock_ports.size()); + fp << "\talways@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_ports[0]) << ") begin" << std::endl; for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) { /* Bypass non-I/O atom blocks ! */ diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.h b/openfpga/src/fpga_verilog/verilog_testbench_utils.h index e432c4650..3683c473c 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.h +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.h @@ -60,8 +60,8 @@ void print_verilog_timeout_and_vcd(std::fstream& fp, const std::string& error_counter_name, const float& simulation_time); -BasicPort generate_verilog_testbench_clock_port(const std::vector& clock_port_names, - const std::string& default_clock_name); +std::vector 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, @@ -77,14 +77,14 @@ void print_verilog_testbench_check(std::fstream& fp, void print_verilog_testbench_clock_stimuli(std::fstream& fp, const SimulationSetting& simulation_parameters, - const BasicPort& clock_port); + const std::vector& clock_ports); void print_verilog_testbench_random_stimuli(std::fstream& fp, const AtomContext& atom_ctx, const VprNetlistAnnotation& netlist_annotation, const std::vector& clock_port_names, const std::string& check_flag_port_postfix, - const BasicPort& clock_port); + const std::vector& clock_ports); void print_verilog_testbench_shared_ports(std::fstream& fp, const AtomContext& atom_ctx, diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index ce21a2e65..f5417e93f 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -288,9 +288,16 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, * 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 == fabric_global_port_info.global_port_default_value(fabric_global_port)); + for (const size_t& pin : module_manager.module_port(top_module, module_global_port).pins()) { + BasicPort global_port_to_connect(module_manager.module_port(top_module, module_global_port).get_name(), pin, pin); + /* TODO: This is a temporary fix to make the testbench generator run in multi-clock scenario + * Need to consider multiple clock sources to connect + * each of which may operate in different ferquency!!! + */ + print_verilog_wire_connection(fp, global_port_to_connect, + stimuli_clock_port, + 1 == fabric_global_port_info.global_port_default_value(fabric_global_port)); + } } /* Connect global configuration done ports to configuration done signal */ @@ -1935,7 +1942,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, netlist_annotation, clock_port_names, std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX), - BasicPort(std::string(TOP_TB_OP_CLOCK_PORT_NAME), 1)); + std::vector(1, BasicPort(std::string(TOP_TB_OP_CLOCK_PORT_NAME), 1))); /* Add output autocheck */ print_verilog_testbench_check(fp,