diff --git a/docs/source/manual/fpga_verilog/figures/mock_fpga_wrapper.png b/docs/source/manual/fpga_verilog/figures/mock_fpga_wrapper.png new file mode 100644 index 000000000..68e8745a1 Binary files /dev/null and b/docs/source/manual/fpga_verilog/figures/mock_fpga_wrapper.png differ diff --git a/docs/source/manual/fpga_verilog/index.rst b/docs/source/manual/fpga_verilog/index.rst index f851e6ed9..d356ff42f 100644 --- a/docs/source/manual/fpga_verilog/index.rst +++ b/docs/source/manual/fpga_verilog/index.rst @@ -10,3 +10,5 @@ FPGA-Verilog fabric_netlist testbench + + mock_fpga_wrapper diff --git a/docs/source/manual/fpga_verilog/mock_fpga_wrapper.rst b/docs/source/manual/fpga_verilog/mock_fpga_wrapper.rst new file mode 100644 index 000000000..a2c9cbd2b --- /dev/null +++ b/docs/source/manual/fpga_verilog/mock_fpga_wrapper.rst @@ -0,0 +1,25 @@ +.. _fpga_verilog_mock_fpga_wrapper: + +Mock FPGA Wrapper +----------------- + +OpenFPGA can generates HDL netlists that model a complete eFPGA fabric (see details in :ref:`fabric_netlists`). +Through bitstream forcing, users can verify the eFPGAs that are mapped by various applications in the context of SoC (see details in :numref:`fig_preconfig_module`). +However, the complete eFPGA fabric is very costly in design verification runtime. +To reduce runtime, a mock eFPGA wrapper is required to bridge the application HDL and other components in the SoC. +As illustrated in :numref:`fig_mock_fpga_wrapper`, a 3-bit counter application is mapped to an FPGA, while a mock wrapper is interfacing the signals between the counter module and the SoC. +The mock wrapper consists of the same ports as the FPGA fabric, which is generated by the OpenFPGA command ``write_fabric_verilog``. See :ref:`openfpga_verilog_commands` for its detailed usage. +The only difference lies in that the mock wrapper contains an instance of the application HDL design which is implemented on the FPGA, while the FPGA fabric contains a complete structure of programmable resources. + +.. note:: The mock wrapper is useful for connectivity checks on FPGA datapaths. It does not cover any configuration protocols (see details in :ref:`config_protocol`) + + +.. _fig_mock_fpga_wrapper: + +.. figure:: figures/mock_fpga_wrapper.png + :width: 100% + :alt: Illustraion of a mock FPGA wrapper + + Principles of a mock FPGA wrapper: ease SoC-level design verification + + diff --git a/docs/source/manual/fpga_verilog/testbench.rst b/docs/source/manual/fpga_verilog/testbench.rst index 6b434e0fb..f4c084620 100644 --- a/docs/source/manual/fpga_verilog/testbench.rst +++ b/docs/source/manual/fpga_verilog/testbench.rst @@ -22,7 +22,7 @@ To enable self-testing, the FPGA and user's RTL design (simulate using an HDL si .. _fig_verilog_testbench_organization: .. figure:: figures/full_testbench_block_diagram.svg - :scale: 50% + :width: 100% :alt: Verilog testbench principles Principles of Verilog testbenches: (1) using common input stimuli; (2) applying bitstream; (3) checking output vectors. @@ -30,7 +30,7 @@ To enable self-testing, the FPGA and user's RTL design (simulate using an HDL si .. _fig_verilog_full_testbench_waveform: .. figure:: figures/full_testbench_waveform.svg - :scale: 50% + :width: 100% :alt: Full testbench waveform Illustration on the waveforms in full testbench @@ -48,7 +48,7 @@ Formal-oriented Testbench The formal-oriented testbench aims to test a programmed FPGA is instantiated with the user's bitstream. The module of the programmed FPGA is encapsulated with the same port mapping as the user's RTL design and thus can be fed to a formal tool for a 100% coverage formal verification. Compared to the full testbench, this skips the time-consuming configuration phase, reducing the simulation time, potentially also significantly accelerating the functional verification, especially for large FPGAs. -.. warning:: Formal-oriented testbenches do not validate the configuration protocol of FPGAs. It is used to validate FPGA with a wide range of benchmarks. +.. warning:: Formal-oriented testbenches do not validate the configuration protocol of FPGAs. It is used to validate FPGA with a wide range of benchmarks. General Usage ~~~~~~~~~~~~~ @@ -59,7 +59,7 @@ Inside the directory, the Verilog testbenches are organized as illustrated in :n .. _fig_verilog_testbench_hierarchy: .. figure:: ./figures/verilog_testbench_hierarchy.svg - :scale: 100% + :width: 100% Hierarchy of Verilog testbenches for a FPGA fabric implemented with an application @@ -91,7 +91,7 @@ Inside the directory, the Verilog testbenches are organized as illustrated in :n .. _fig_preconfig_module: .. figure:: ./figures/preconfig_module.png - :scale: 25% + :width: 100% Internal structure of a pre-configured FPGA module diff --git a/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst b/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst index 6a872a1d1..b085df0bf 100644 --- a/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst +++ b/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst @@ -166,6 +166,45 @@ __ iverilog_website_ Show verbose log +write_mock_fpga_wrapper +~~~~~~~~~~~~~~~~~~~~~~~ + + Write the Verilog wrapper which mockes a mapped FPGA fabric. See details in :ref:`fpga_verilog_mock_fpga_wrapper`. + + .. option:: --file or -f + + The output directory for the netlists. We suggest the use of same output directory as fabric Verilog netlists. For example, ``--file /temp/testbench`` + + .. option:: --pin_constraints_file or -pcf + + Specify the *Pin Constraints File* (PCF) if you want to custom stimulus in testbenches. For example, ``-pin_constraints_file pin_constraints.xml`` + Strongly recommend for multi-clock simulations. See detailed file format about :ref:`file_format_pin_constraints_file`. + + .. option:: --bus_group_file or -bgf + + Specify the *Bus Group File* (BGF) if you want to group pins to buses. For example, ``-bgf bus_group.xml`` + Strongly recommend when input HDL contains bus ports. See detailed file format about :ref:`file_format_bus_group_file`. + + .. option:: --explicit_port_mapping + + Use explicit port mapping when writing the Verilog netlists + + .. option:: --use_relative_path + + Force to use relative path in netlists when including other netlists. By default, this is off, which means that netlists use absolute paths when including other netlists + + .. option:: --default_net_type + + Specify the default net type for the Verilog netlists. Currently, supported types are ``none`` and ``wire``. Default value: ``none``. + + .. option:: --no_time_stamp + + Do not print time stamp in Verilog netlists + + .. option:: --verbose + + Show verbose log + write_preconfigured_testbench ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/openfpga/src/base/openfpga_verilog_command_template.h b/openfpga/src/base/openfpga_verilog_command_template.h index 266afc6d8..010b73802 100644 --- a/openfpga/src/base/openfpga_verilog_command_template.h +++ b/openfpga/src/base/openfpga_verilog_command_template.h @@ -251,6 +251,78 @@ ShellCommandId add_write_preconfigured_fabric_wrapper_command_template( return shell_cmd_id; } +/******************************************************************** + * - add a command to shell environment: write mock fpga wrapper + * - add associated options + * - add command dependency + *******************************************************************/ +template +ShellCommandId add_write_mock_fpga_wrapper_command_template( + openfpga::Shell& shell, const ShellCommandClassId& cmd_class_id, + const std::vector& dependent_cmds, const bool& hidden) { + Command shell_cmd("write_mock_fpga_wrapper"); + + /* add an option '--file' in short '-f'*/ + CommandOptionId output_opt = shell_cmd.add_option( + "file", true, "specify the output directory for hdl netlists"); + shell_cmd.set_option_short_name(output_opt, "f"); + shell_cmd.set_option_require_value(output_opt, openfpga::OPT_STRING); + + /* add an option '--pin_constraints_file in short '-pcf' */ + CommandOptionId pcf_opt = + shell_cmd.add_option("pin_constraints_file", false, + "specify the file path to the pin constraints"); + shell_cmd.set_option_short_name(pcf_opt, "pcf"); + shell_cmd.set_option_require_value(pcf_opt, openfpga::OPT_STRING); + + /* add an option '--bus_group_file in short '-bgf' */ + CommandOptionId bgf_opt = shell_cmd.add_option( + "bus_group_file", false, "specify the file path to the group pins to bus"); + shell_cmd.set_option_short_name(bgf_opt, "bgf"); + shell_cmd.set_option_require_value(bgf_opt, openfpga::OPT_STRING); + + /* Add an option '--use_relative_path' */ + shell_cmd.add_option( + "use_relative_path", false, + "Force to use relative path in netlists when including other netlists"); + + /* add an option '--explicit_port_mapping' */ + shell_cmd.add_option("explicit_port_mapping", false, + "use explicit port mapping in verilog netlists"); + + /* Add an option '--default_net_type' */ + CommandOptionId default_net_type_opt = shell_cmd.add_option( + "default_net_type", false, + "Set the default net type for Verilog netlists. Default value is 'none'"); + shell_cmd.set_option_require_value(default_net_type_opt, + openfpga::OPT_STRING); + + /* add an option '--explicit_port_mapping' */ + shell_cmd.add_option("explicit_port_mapping", false, + "use explicit port mapping in verilog netlists"); + + /* Add an option '--no_time_stamp' */ + shell_cmd.add_option("no_time_stamp", false, + "Do not print a time stamp in the output files"); + + /* add an option '--verbose' */ + shell_cmd.add_option("verbose", false, "enable verbose output"); + + /* add command to the shell */ + ShellCommandId shell_cmd_id = shell.add_command( + shell_cmd, + "generate a wrapper of a mock fpga fabric mapped with applications", + hidden); + shell.set_command_class(shell_cmd_id, cmd_class_id); + shell.set_command_execute_function(shell_cmd_id, + write_mock_fpga_wrapper_template); + + /* add command dependency to the shell */ + shell.set_command_dependency(shell_cmd_id, dependent_cmds); + + return shell_cmd_id; +} + /******************************************************************** * - Add a command to Shell environment: write preconfigured testbench * - Add associated options @@ -435,6 +507,17 @@ void add_verilog_command_templates(openfpga::Shell& shell, shell, openfpga_verilog_cmd_class, preconfig_wrapper_dependent_cmds, hidden); + /******************************** + * Command 'write_mock_fpga_wrapper' + */ + /* The command 'write_mock_fpga_wrapper' should NOT be executed + * before 'build_fabric' */ + std::vector write_mock_fpga_wrapper_dependent_cmds; + write_mock_fpga_wrapper_dependent_cmds.push_back(build_fabric_cmd_id); + add_write_mock_fpga_wrapper_command_template( + shell, openfpga_verilog_cmd_class, write_mock_fpga_wrapper_dependent_cmds, + hidden); + /******************************** * Command 'write_preconfigured_testbench' */ diff --git a/openfpga/src/base/openfpga_verilog_template.h b/openfpga/src/base/openfpga_verilog_template.h index 3f042ddcc..a25ce81c1 100644 --- a/openfpga/src/base/openfpga_verilog_template.h +++ b/openfpga/src/base/openfpga_verilog_template.h @@ -12,6 +12,7 @@ #include "read_xml_bus_group.h" #include "read_xml_pin_constraints.h" #include "verilog_api.h" +#include "verilog_mock_fpga_wrapper.h" #include "vtr_log.h" #include "vtr_time.h" @@ -207,6 +208,61 @@ int write_preconfigured_fabric_wrapper_template( openfpga_ctx.arch().config_protocol, options); } +/******************************************************************** + * A wrapper function to call the mock fpga wrapper generator of + *FPGA-Verilog + *******************************************************************/ +template +int write_mock_fpga_wrapper_template(const T& openfpga_ctx, const Command& cmd, + const CommandContext& cmd_context) { + CommandOptionId opt_output_dir = cmd.option("file"); + CommandOptionId opt_pcf = cmd.option("pin_constraints_file"); + CommandOptionId opt_bgf = cmd.option("bus_group_file"); + CommandOptionId opt_explicit_port_mapping = + cmd.option("explicit_port_mapping"); + CommandOptionId opt_use_relative_path = cmd.option("use_relative_path"); + CommandOptionId opt_default_net_type = cmd.option("default_net_type"); + CommandOptionId opt_no_time_stamp = cmd.option("no_time_stamp"); + CommandOptionId opt_verbose = cmd.option("verbose"); + + /* This is an intermediate data structure which is designed to modularize the + * FPGA-Verilog Keep it independent from any other outside data structures + */ + VerilogTestbenchOption options; + options.set_output_directory(cmd_context.option_value(cmd, opt_output_dir)); + options.set_explicit_port_mapping( + cmd_context.option_enable(cmd, opt_explicit_port_mapping)); + options.set_use_relative_path( + cmd_context.option_enable(cmd, opt_use_relative_path)); + options.set_time_stamp(!cmd_context.option_enable(cmd, opt_no_time_stamp)); + options.set_verbose_output(cmd_context.option_enable(cmd, opt_verbose)); + + if (true == cmd_context.option_enable(cmd, opt_default_net_type)) { + options.set_default_net_type( + cmd_context.option_value(cmd, opt_default_net_type)); + } + + /* If pin constraints are enabled by command options, read the file */ + PinConstraints pin_constraints; + if (true == cmd_context.option_enable(cmd, opt_pcf)) { + pin_constraints = + read_xml_pin_constraints(cmd_context.option_value(cmd, opt_pcf).c_str()); + } + + /* If bug group file are enabled by command options, read the file */ + BusGroup bus_group; + if (true == cmd_context.option_enable(cmd, opt_bgf)) { + bus_group = + read_xml_bus_group(cmd_context.option_value(cmd, opt_bgf).c_str()); + } + + return fpga_verilog_mock_fpga_wrapper( + openfpga_ctx.module_graph(), g_vpr_ctx.atom(), g_vpr_ctx.placement(), + pin_constraints, bus_group, openfpga_ctx.io_location_map(), + openfpga_ctx.fabric_global_port_info(), + openfpga_ctx.vpr_netlist_annotation(), options); +} + /******************************************************************** * A wrapper function to call the preconfigured testbench generator of *FPGA-Verilog diff --git a/openfpga/src/fpga_verilog/verilog_api.cpp b/openfpga/src/fpga_verilog/verilog_api.cpp index 3fa929afc..4bc5e6ced 100644 --- a/openfpga/src/fpga_verilog/verilog_api.cpp +++ b/openfpga/src/fpga_verilog/verilog_api.cpp @@ -12,11 +12,13 @@ /* Headers from openfpgautil library */ #include "device_rr_gsb.h" #include "openfpga_digest.h" +#include "openfpga_naming.h" #include "openfpga_reserved_words.h" #include "verilog_auxiliary_netlists.h" #include "verilog_constants.h" #include "verilog_formal_random_top_testbench.h" #include "verilog_grid.h" +#include "verilog_mock_fpga_wrapper.h" #include "verilog_preconfig_top_module.h" #include "verilog_routing.h" #include "verilog_simulation_info_writer.h" @@ -222,6 +224,60 @@ int fpga_verilog_preconfigured_fabric_wrapper( return status; } +/******************************************************************** + * A top-level function of FPGA-Verilog which focuses on a wrapper module, + * which encapsulate the application HDL into a mock FPGA module + ********************************************************************/ +int fpga_verilog_mock_fpga_wrapper( + const ModuleManager &module_manager, const AtomContext &atom_ctx, + const PlacementContext &place_ctx, const PinConstraints &pin_constraints, + const BusGroup &bus_group, const IoLocationMap &io_location_map, + const FabricGlobalPortInfo &fabric_global_port_info, + const VprNetlistAnnotation &netlist_annotation, + const VerilogTestbenchOption &options) { + vtr::ScopedStartFinishTimer timer( + "Write a wrapper module to mock a mapped FPGA fabric\n"); + + std::string src_dir_path = format_dir_path(options.output_directory()); + + std::string netlist_name = atom_ctx.nlist.netlist_name(); + + int status = CMD_EXEC_SUCCESS; + + NetlistManager netlist_manager; + + /* Create directories */ + create_directory(src_dir_path); + + /* Generate wrapper module for FPGA fabric (mapped by the input benchmark and + * pre-configured testbench for verification */ + std::string netlist_file_name = + generate_fpga_top_netlist_name(std::string(VERILOG_NETLIST_FILE_POSTFIX)); + std::string netlist_file_path = src_dir_path + netlist_file_name; + status = print_verilog_mock_fpga_wrapper( + module_manager, fabric_global_port_info, atom_ctx, place_ctx, + pin_constraints, bus_group, io_location_map, netlist_annotation, + netlist_name, netlist_file_path, options); + + /* Add fname to the netlist name list */ + NetlistId nlist_id = NetlistId::INVALID(); + if (options.use_relative_path()) { + nlist_id = netlist_manager.add_netlist(netlist_file_name); + } else { + nlist_id = netlist_manager.add_netlist(netlist_file_path); + } + VTR_ASSERT(nlist_id); + netlist_manager.set_netlist_type(nlist_id, + NetlistManager::TOP_MODULE_NETLIST); + + /* Generate an netlist including all the fabric-related netlists */ + print_verilog_mock_fabric_include_netlist(netlist_manager, src_dir_path, + options.use_relative_path(), + options.time_stamp()); + + return status; +} + /******************************************************************** * A top-level function of FPGA-Verilog which focuses on fabric Verilog *generation This function will generate diff --git a/openfpga/src/fpga_verilog/verilog_api.h b/openfpga/src/fpga_verilog/verilog_api.h index 79ce6759d..914e58d70 100644 --- a/openfpga/src/fpga_verilog/verilog_api.h +++ b/openfpga/src/fpga_verilog/verilog_api.h @@ -68,6 +68,14 @@ int fpga_verilog_preconfigured_fabric_wrapper( const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol, const VerilogTestbenchOption& options); +int fpga_verilog_mock_fpga_wrapper( + const ModuleManager& module_manager, const AtomContext& atom_ctx, + const PlacementContext& place_ctx, const PinConstraints& pin_constraints, + const BusGroup& bus_group, const IoLocationMap& io_location_map, + const FabricGlobalPortInfo& fabric_global_port_info, + const VprNetlistAnnotation& netlist_annotation, + const VerilogTestbenchOption& options); + int fpga_verilog_preconfigured_testbench( const ModuleManager& module_manager, const AtomContext& atom_ctx, const PinConstraints& pin_constraints, const BusGroup& bus_group, diff --git a/openfpga/src/fpga_verilog/verilog_auxiliary_netlists.cpp b/openfpga/src/fpga_verilog/verilog_auxiliary_netlists.cpp index aa600ddba..a19ee9446 100644 --- a/openfpga/src/fpga_verilog/verilog_auxiliary_netlists.cpp +++ b/openfpga/src/fpga_verilog/verilog_auxiliary_netlists.cpp @@ -23,6 +23,48 @@ namespace openfpga { * Local constant variables *******************************************************************/ +/******************************************************************** + * Print a file that includes all the fabric netlists + * that have been generated and user-defined. + * This does NOT include any testbenches! + * Some netlists are open to compile under specific preprocessing flags + *******************************************************************/ +void print_verilog_mock_fabric_include_netlist( + const NetlistManager& netlist_manager, const std::string& src_dir_path, + const bool& use_relative_path, const bool& include_time_stamp) { + /* If we force the use of relative path, the src dir path should NOT be + * included in any output */ + std::string src_dir = src_dir_path; + if (use_relative_path) { + src_dir.clear(); + } + std::string verilog_fpath = + src_dir_path + std::string(FABRIC_INCLUDE_VERILOG_NETLIST_FILE_NAME); + + /* Create the file stream */ + std::fstream fp; + fp.open(verilog_fpath, std::fstream::out | std::fstream::trunc); + + /* Validate the file stream */ + check_file_stream(verilog_fpath.c_str(), fp); + + /* Print the title */ + print_verilog_file_header(fp, std::string("Mock Fabric Netlist Summary"), + include_time_stamp); + + /* Include FPGA top module */ + print_verilog_comment( + fp, std::string("------ Include fabric top-level netlists -----")); + for (const NetlistId& nlist_id : + netlist_manager.netlists_by_type(NetlistManager::TOP_MODULE_NETLIST)) { + print_verilog_include_netlist(fp, netlist_manager.netlist_name(nlist_id)); + } + fp << std::endl; + + /* Close the file stream */ + fp.close(); +} + /******************************************************************** * Print a file that includes all the fabric netlists * that have been generated and user-defined. diff --git a/openfpga/src/fpga_verilog/verilog_auxiliary_netlists.h b/openfpga/src/fpga_verilog/verilog_auxiliary_netlists.h index 553c8c3a4..493f2c4af 100644 --- a/openfpga/src/fpga_verilog/verilog_auxiliary_netlists.h +++ b/openfpga/src/fpga_verilog/verilog_auxiliary_netlists.h @@ -18,6 +18,10 @@ /* begin namespace openfpga */ namespace openfpga { +void print_verilog_mock_fabric_include_netlist( + const NetlistManager& netlist_manager, const std::string& src_dir_path, + const bool& use_relative_path, const bool& include_time_stamp); + void print_verilog_fabric_include_netlist(const NetlistManager& netlist_manager, const std::string& src_dir_path, const CircuitLibrary& circuit_lib, 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 c72eb6786..629d1759b 100644 --- a/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.cpp @@ -116,8 +116,9 @@ static void print_verilog_top_random_testbench_benchmark_instance( print_verilog_testbench_benchmark_instance( fp, reference_verilog_top_name, std::string(BENCHMARK_INSTANCE_NAME), std::string(), std::string(), std::string(), - std::string(BENCHMARK_PORT_POSTFIX), std::vector(), atom_ctx, - netlist_annotation, pin_constraints, bus_group, explicit_port_mapping); + std::string(BENCHMARK_PORT_POSTFIX), std::vector(), false, + atom_ctx, netlist_annotation, pin_constraints, bus_group, + explicit_port_mapping); print_verilog_comment( fp, std::string("----- End reference Benchmark Instanication -------")); @@ -147,7 +148,7 @@ static void print_verilog_random_testbench_fpga_instance( std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX)), std::string(FPGA_INSTANCE_NAME), std::string(), std::string(), std::string(), std::string(FPGA_PORT_POSTFIX), std::vector(), - atom_ctx, netlist_annotation, pin_constraints, bus_group, + false, atom_ctx, netlist_annotation, pin_constraints, bus_group, explicit_port_mapping); print_verilog_comment( diff --git a/openfpga/src/fpga_verilog/verilog_mock_fpga_wrapper.cpp b/openfpga/src/fpga_verilog/verilog_mock_fpga_wrapper.cpp new file mode 100644 index 000000000..a28b9ffaa --- /dev/null +++ b/openfpga/src/fpga_verilog/verilog_mock_fpga_wrapper.cpp @@ -0,0 +1,491 @@ +/******************************************************************** + * This file includes functions that are used to generate + * a Verilog module of a pre-configured FPGA fabric + *******************************************************************/ +#include + +/* Headers from vtrutil library */ +#include "command_exit_codes.h" +#include "vtr_assert.h" +#include "vtr_log.h" +#include "vtr_time.h" + +/* Headers from openfpgautil library */ +#include "bitstream_manager_utils.h" +#include "fabric_global_port_info_utils.h" +#include "module_manager_utils.h" +#include "openfpga_atom_netlist_utils.h" +#include "openfpga_digest.h" +#include "openfpga_naming.h" +#include "openfpga_port.h" +#include "openfpga_reserved_words.h" +#include "verilog_constants.h" +#include "verilog_mock_fpga_wrapper.h" +#include "verilog_testbench_utils.h" +#include "verilog_writer_utils.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/******************************************************************** + * Local variables used only in this file + *******************************************************************/ +constexpr const char* APPINST_PORT_POSTFIX = "_bench"; +constexpr const char* APP_INSTANCE_NAME = "MAPPED_DESIGN"; + +/******************************************************************** + * 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_mock_fpga_wrapper_connect_ios( + std::fstream& fp, const ModuleManager& module_manager, + const ModuleId& top_module, const AtomContext& atom_ctx, + const PlacementContext& place_ctx, const IoLocationMap& io_location_map, + const PinConstraints& pin_constraints, + const FabricGlobalPortInfo& global_ports, + const VprNetlistAnnotation& netlist_annotation, + const std::string& net_name_postfix, + const std::string& io_input_port_name_postfix, + const std::string& io_output_port_name_postfix, + const std::vector& clock_port_names, + const size_t& unused_io_value) { + /* Validate the file stream */ + valid_file_stream(fp); + + /* Only mappable i/o ports can be considered */ + std::vector module_io_ports; + for (const ModuleManager::e_module_port_type& module_io_port_type : + MODULE_IO_PORT_TYPES) { + for (const ModulePortId& gpio_port_id : + module_manager.module_port_ids_by_type(top_module, + module_io_port_type)) { + /* Only care mappable I/O */ + if (false == + module_manager.port_is_mappable_io(top_module, gpio_port_id)) { + continue; + } + module_io_ports.push_back(gpio_port_id); + } + } + + /* Keep tracking which I/Os have been used */ + std::map> io_used; + for (const ModulePortId& module_io_port_id : module_io_ports) { + const BasicPort& module_io_port = + module_manager.module_port(top_module, module_io_port_id); + io_used[module_io_port_id] = + std::vector(module_io_port.get_width(), false); + } + + /* Type mapping between VPR block and Module port */ + std::map + atom_block_type_to_module_port_type; + atom_block_type_to_module_port_type[AtomBlockType::INPAD] = + ModuleManager::MODULE_GPIN_PORT; + atom_block_type_to_module_port_type[AtomBlockType::OUTPAD] = + ModuleManager::MODULE_GPOUT_PORT; + + /* 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 FPGA I/Os to Benchmark I/Os -----")); + + for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) { + /* Bypass non-I/O atom blocks ! */ + if ((AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk)) && + (AtomBlockType::OUTPAD != atom_ctx.nlist.block_type(atom_blk))) { + continue; + } + + /* If there is a GPIO port, use it directly + * Otherwise, should find a GPIN for INPAD + * or should find a GPOUT for OUTPAD + */ + std::pair mapped_module_io_info = + std::make_pair(ModulePortId::INVALID(), -1); + for (const ModulePortId& module_io_port_id : module_io_ports) { + const BasicPort& module_io_port = + module_manager.module_port(top_module, module_io_port_id); + + /* Find the index of the mapped GPIO in top-level FPGA fabric */ + size_t temp_io_index = io_location_map.io_index( + place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.x, + place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.y, + place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.sub_tile, + module_io_port.get_name()); + + /* Bypass invalid index (not mapped to this GPIO port) */ + if (size_t(-1) == temp_io_index) { + continue; + } + + /* If the port is an GPIO port, just use it */ + if (ModuleManager::MODULE_GPIO_PORT == + module_manager.port_type(top_module, module_io_port_id)) { + mapped_module_io_info = + std::make_pair(module_io_port_id, temp_io_index); + break; + } + + /* If this is an INPAD, we can use an GPIN port (if available) */ + if (atom_block_type_to_module_port_type[atom_ctx.nlist.block_type( + atom_blk)] == + module_manager.port_type(top_module, module_io_port_id)) { + mapped_module_io_info = + std::make_pair(module_io_port_id, temp_io_index); + break; + } + } + + /* We must find a valid one */ + VTR_ASSERT(true == module_manager.valid_module_port_id( + top_module, mapped_module_io_info.first)); + VTR_ASSERT(size_t(-1) != mapped_module_io_info.second); + + /* Ensure that IO index is in range */ + BasicPort module_mapped_io_port = + module_manager.module_port(top_module, mapped_module_io_info.first); + size_t io_index = mapped_module_io_info.second; + + /* Set the port pin index */ + VTR_ASSERT(io_index < module_mapped_io_port.get_width()); + module_mapped_io_port.set_name(module_mapped_io_port.get_name() + + net_name_postfix); + module_mapped_io_port.set_width(io_index, io_index); + + /* The block may be renamed as it contains special characters which violate + * Verilog syntax */ + std::string block_name = atom_ctx.nlist.block_name(atom_blk); + if (true == netlist_annotation.is_block_renamed(atom_blk)) { + block_name = netlist_annotation.block_name(atom_blk); + } + /* Note that VPR added a prefix to the name of output blocks + * We can remove this when specified through input argument + */ + if (AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk)) { + block_name = remove_atom_block_name_prefix(block_name); + } + + /* 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; + + benchmark_io_port.set_width(1); + + if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) { + /* If the port is a clock, skip it */ + if (clock_port_names.end() != std::find(clock_port_names.begin(), + clock_port_names.end(), + block_name)) { + continue; + } + /* For global ports, use wires; otherwise, use registers*/ + if (true == port_is_fabric_global_reset_port( + global_ports, module_manager, + pin_constraints.net_pin(block_name))) { + continue; + } + + benchmark_io_port.set_name( + std::string(block_name + io_input_port_name_postfix)); + print_verilog_comment( + fp, std::string("----- Blif Benchmark input " + block_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); + } else { + VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk)); + benchmark_io_port.set_name( + std::string(block_name + io_output_port_name_postfix)); + print_verilog_comment( + fp, std::string("----- Blif Benchmark output " + block_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); + } + + /* Mark this I/O has been used/wired */ + io_used[mapped_module_io_info.first][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 (const ModulePortId& module_io_port_id : module_io_ports) { + for (size_t io_index = 0; io_index < io_used[module_io_port_id].size(); + ++io_index) { + /* Bypass used iopads */ + if (true == io_used[module_io_port_id][io_index]) { + continue; + } + + /* Bypass unused output pads */ + if (ModuleManager::MODULE_GPOUT_PORT != + module_manager.port_type(top_module, module_io_port_id)) { + continue; + } + + /* Wire to a contant */ + BasicPort module_unused_io_port = + module_manager.module_port(top_module, module_io_port_id); + /* Set the port pin index */ + module_unused_io_port.set_name(module_unused_io_port.get_name() + + net_name_postfix); + 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; + } +} + +/******************************************************************** + * Connect global ports of FPGA top module to constants except: + * 1. operating clock, which should be wired to the clock port of + * this pre-configured FPGA top module + *******************************************************************/ +static int print_verilog_mock_fpga_wrapper_connect_global_ports( + std::fstream& fp, const ModuleManager& module_manager, + const ModuleId& top_module, const PinConstraints& pin_constraints, + const FabricGlobalPortInfo& fabric_global_ports, + const std::vector& benchmark_clock_port_names) { + /* Validate the file stream */ + valid_file_stream(fp); + + print_verilog_comment( + fp, + std::string( + "----- Begin Connect Global ports to FPGA top-level interface -----")); + + for (const FabricGlobalPortId& global_port_id : + fabric_global_ports.global_ports()) { + ModulePortId module_global_port_id = + fabric_global_ports.global_module_port(global_port_id); + VTR_ASSERT(ModuleManager::MODULE_GLOBAL_PORT == + module_manager.port_type(top_module, module_global_port_id)); + BasicPort module_global_port = + module_manager.module_port(top_module, module_global_port_id); + /* Now, for operating clock port, we should wire it to the clock of + * benchmark! */ + if ((true == fabric_global_ports.global_port_is_clock(global_port_id)) && + (false == fabric_global_ports.global_port_is_prog(global_port_id))) { + /* Wiring to each pin of the global port: benchmark clock is always 1-bit + */ + for (size_t pin_id = 0; pin_id < module_global_port.pins().size(); + ++pin_id) { + BasicPort module_clock_pin(module_global_port.get_name(), + module_global_port.pins()[pin_id], + module_global_port.pins()[pin_id]); + + /* If the clock port name is in the pin constraints, we should wire it + * to the constrained pin */ + std::string constrained_net_name = pin_constraints.pin_net(BasicPort( + module_global_port.get_name(), module_global_port.pins()[pin_id], + module_global_port.pins()[pin_id])); + + /* If constrained to an open net or there is no clock in the benchmark, + * we assign it to a default value */ + if ((true == pin_constraints.unmapped_net(constrained_net_name)) || + (true == benchmark_clock_port_names.empty())) { + continue; + } + + std::string clock_name_to_connect; + if (!pin_constraints.unconstrained_net(constrained_net_name)) { + clock_name_to_connect = constrained_net_name; + } else { + /* Otherwise, we must have a clear one-to-one clock net + * corresponding!!! */ + if (benchmark_clock_port_names.size() != + module_global_port.get_width()) { + VTR_LOG_ERROR( + "Unable to map %lu benchmark clocks to %lu clock pins of " + "FPGA!\nRequire clear pin constraints!\n", + benchmark_clock_port_names.size(), + module_global_port.get_width()); + return CMD_EXEC_FATAL_ERROR; + } + clock_name_to_connect = benchmark_clock_port_names[pin_id]; + } + clock_name_to_connect += std::string(APPINST_PORT_POSTFIX); + + BasicPort benchmark_clock_pin(clock_name_to_connect, 1); + print_verilog_wire_connection(fp, benchmark_clock_pin, module_clock_pin, + false); + } + /* Finish, go to the next */ + continue; + } + + /* For other ports, give an default value */ + for (size_t pin_id = 0; pin_id < module_global_port.pins().size(); + ++pin_id) { + BasicPort module_global_pin(module_global_port.get_name(), + module_global_port.pins()[pin_id], + module_global_port.pins()[pin_id]); + + /* If the global port name is in the pin constraints, we should wire it to + * the constrained pin */ + std::string constrained_net_name = + pin_constraints.pin_net(module_global_pin); + if (constrained_net_name.empty()) { + continue; + } + constrained_net_name += std::string(APPINST_PORT_POSTFIX); + + module_global_pin.set_name(module_global_port.get_name()); + + /* - If constrained to a given net in the benchmark, we connect the global + * pin to the net + * - If constrained to an open net in the benchmark, we assign it to a + * default value + */ + if ((false == pin_constraints.unconstrained_net(constrained_net_name)) && + (false == pin_constraints.unmapped_net(constrained_net_name))) { + BasicPort benchmark_pin(constrained_net_name, 1); + print_verilog_wire_connection(fp, benchmark_pin, module_global_pin, + false); + } + } + } + + print_verilog_comment( + fp, std::string( + "----- End Connect Global ports to FPGA top-level interface -----")); + + /* Add an empty line as a splitter */ + fp << std::endl; + + return CMD_EXEC_SUCCESS; +} + +/******************************************************************** + * Top-level function to generate a Verilog module of + * a mock FPGA wrapper which contains an benchmark instance. + * + * Mock FPGA wrapper + * +-------------------------------------------- + * | + * | Benchmark instance + * | +-------------------------------+ + * | | | + * fpga_clock----->|--------->|benchmark_clock | + * | | | + * fpga_inputs---->|--------->|benchmark_inputs | + * | | | + * fpga_outputs<---|<---------|benchmark_output | + * | | | + * | +-------------------------------+ + * | + * +------------------------------------------- + * + * Note: we do NOT put this module in the module manager. + * Because, it is not a standard module, where we just wrap an instance of + *application HDL (supposed to be implemented on FPGA). + *******************************************************************/ +int print_verilog_mock_fpga_wrapper( + const ModuleManager& module_manager, const FabricGlobalPortInfo& global_ports, + const AtomContext& atom_ctx, const PlacementContext& place_ctx, + const PinConstraints& pin_constraints, const BusGroup& bus_group, + const IoLocationMap& io_location_map, + const VprNetlistAnnotation& netlist_annotation, + const std::string& circuit_name, const std::string& verilog_fname, + const VerilogTestbenchOption& options) { + std::string timer_message = + std::string("Write mock FPGA wrapper in Verilog format for design '") + + circuit_name + std::string("'"); + + int status = CMD_EXEC_SUCCESS; + + /* Start time count */ + vtr::ScopedStartFinishTimer timer(timer_message); + + /* Create the file stream */ + std::fstream fp; + fp.open(verilog_fname, std::fstream::out | std::fstream::trunc); + + /* Validate the file stream */ + check_file_stream(verilog_fname.c_str(), fp); + + /* Generate a brief description on the Verilog file*/ + std::string title = + std::string("Verilog netlist for mock FPGA fabric by design: ") + + circuit_name; + print_verilog_file_header(fp, title, options.time_stamp()); + + /* 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)); + + /* Print module declaration */ + print_verilog_module_declaration(fp, module_manager, top_module, + options.default_net_type()); + + /* Find clock ports in benchmark */ + std::vector benchmark_clock_port_names = + find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation); + + /* Print local wires */ + print_verilog_testbench_shared_input_ports( + fp, module_manager, global_ports, pin_constraints, atom_ctx, + netlist_annotation, benchmark_clock_port_names, true, + std::string(APPINST_PORT_POSTFIX), false); + + print_verilog_testbench_shared_benchmark_output_ports( + fp, atom_ctx, netlist_annotation, std::string(APPINST_PORT_POSTFIX)); + + /* Instanciate application HDL module */ + print_verilog_testbench_benchmark_instance( + fp, circuit_name, std::string(APP_INSTANCE_NAME), std::string(), + std::string(), std::string(APPINST_PORT_POSTFIX), + std::string(APPINST_PORT_POSTFIX), benchmark_clock_port_names, true, + atom_ctx, netlist_annotation, pin_constraints, bus_group, + options.explicit_port_mapping()); + + /* Connect FPGA top module global ports to constant or benchmark global + * signals! */ + status = print_verilog_mock_fpga_wrapper_connect_global_ports( + fp, module_manager, top_module, pin_constraints, global_ports, + benchmark_clock_port_names); + if (CMD_EXEC_FATAL_ERROR == status) { + return status; + } + + /* Connect I/Os to benchmark I/Os or constant driver */ + print_verilog_mock_fpga_wrapper_connect_ios( + fp, module_manager, top_module, atom_ctx, place_ctx, io_location_map, + pin_constraints, global_ports, netlist_annotation, std::string(), + std::string(APPINST_PORT_POSTFIX), std::string(APPINST_PORT_POSTFIX), + benchmark_clock_port_names, (size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE); + + /* Testbench ends*/ + print_verilog_module_end(fp, title); + + /* Close the file stream */ + fp.close(); + + return status; +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/fpga_verilog/verilog_mock_fpga_wrapper.h b/openfpga/src/fpga_verilog/verilog_mock_fpga_wrapper.h new file mode 100644 index 000000000..62f2f5d71 --- /dev/null +++ b/openfpga/src/fpga_verilog/verilog_mock_fpga_wrapper.h @@ -0,0 +1,40 @@ +#ifndef VERILOG_MOCK_FPGA_WRAPPER_H +#define VERILOG_MOCK_FPGA_WRAPPER_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include + +#include "bitstream_manager.h" +#include "bus_group.h" +#include "circuit_library.h" +#include "config_protocol.h" +#include "fabric_global_port_info.h" +#include "io_location_map.h" +#include "module_manager.h" +#include "pin_constraints.h" +#include "verilog_testbench_options.h" +#include "vpr_context.h" +#include "vpr_netlist_annotation.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +int print_verilog_mock_fpga_wrapper( + const ModuleManager& module_manager, const FabricGlobalPortInfo& global_ports, + const AtomContext& atom_ctx, const PlacementContext& place_ctx, + const PinConstraints& pin_constraints, const BusGroup& bus_group, + const IoLocationMap& io_location_map, + const VprNetlistAnnotation& netlist_annotation, + const std::string& circuit_name, const std::string& verilog_fname, + const VerilogTestbenchOption& options); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp index 8c91e50d0..09c900b3b 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp @@ -78,7 +78,8 @@ void print_verilog_testbench_benchmark_instance( const std::string& module_input_port_postfix, const std::string& module_output_port_postfix, const std::string& input_port_postfix, const std::string& output_port_postfix, - const std::vector& clock_port_names, const AtomContext& atom_ctx, + const std::vector& clock_port_names, + const bool& include_clock_port_postfix, const AtomContext& atom_ctx, const VprNetlistAnnotation& netlist_annotation, const PinConstraints& pin_constraints, const BusGroup& bus_group, const bool& use_explicit_port_map) { @@ -183,6 +184,8 @@ void print_verilog_testbench_benchmark_instance( clock_port_names.end(), port_names[iport])) { fp << input_port_postfix; + } else if (include_clock_port_postfix) { + fp << input_port_postfix; } pin_counter++; @@ -206,6 +209,8 @@ void print_verilog_testbench_benchmark_instance( clock_port_names.end(), port_names[iport])) { fp << input_port_postfix; + } else if (include_clock_port_postfix) { + fp << input_port_postfix; } } @@ -914,20 +919,16 @@ void print_verilog_testbench_random_stimuli( * 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( +void print_verilog_testbench_shared_input_ports( std::fstream& fp, const ModuleManager& module_manager, const FabricGlobalPortInfo& global_ports, const PinConstraints& pin_constraints, const AtomContext& atom_ctx, const VprNetlistAnnotation& netlist_annotation, const std::vector& clock_port_names, - const std::string& shared_input_port_postfix, - const std::string& benchmark_output_port_postfix, - const std::string& fpga_output_port_postfix, - const std::string& check_flag_port_postfix, const bool& no_self_checking) { + const bool& include_clock_ports, const std::string& shared_input_port_postfix, + const bool& use_reg_port) { /* Validate the file stream */ valid_file_stream(fp); @@ -950,7 +951,9 @@ void print_verilog_testbench_shared_ports( if (clock_port_names.end() != std::find(clock_port_names.begin(), clock_port_names.end(), block_name)) { - continue; + if (!include_clock_ports) { + continue; + } } /* Each logical block assumes a single-width port */ @@ -959,8 +962,13 @@ void print_verilog_testbench_shared_ports( if (false == port_is_fabric_global_reset_port(global_ports, module_manager, pin_constraints.net_pin(block_name))) { - fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, input_port) << ";" - << std::endl; + if (use_reg_port) { + fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, input_port) << ";" + << std::endl; + } else { + fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, input_port) + << ";" << std::endl; + } } else { fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, input_port) << ";" << std::endl; @@ -969,6 +977,19 @@ void print_verilog_testbench_shared_ports( /* Add an empty line as splitter */ fp << std::endl; +} + +/******************************************************************** + * Print Verilog declaration of shared ports appear in testbenches + * which are + * 2. the output ports (wires) for FPGA fabric + *******************************************************************/ +void print_verilog_testbench_shared_fpga_output_ports( + std::fstream& fp, const AtomContext& atom_ctx, + const VprNetlistAnnotation& netlist_annotation, + const std::string& fpga_output_port_postfix) { + /* Validate the file stream */ + valid_file_stream(fp); /* Instantiate wires for FPGA fabric outputs */ print_verilog_comment(fp, std::string("----- FPGA fabric outputs -------")); @@ -996,10 +1017,19 @@ void print_verilog_testbench_shared_ports( /* Add an empty line as splitter */ fp << std::endl; +} - if (no_self_checking) { - return; - } +/******************************************************************** + * Print Verilog declaration of shared ports appear in testbenches + * which are + * 2. the output ports (wires) for benchmark instance + *******************************************************************/ +void print_verilog_testbench_shared_benchmark_output_ports( + std::fstream& fp, const AtomContext& atom_ctx, + const VprNetlistAnnotation& netlist_annotation, + const std::string& benchmark_output_port_postfix) { + /* Validate the file stream */ + valid_file_stream(fp); /* Instantiate wire for benchmark output */ print_verilog_comment(fp, std::string("----- Benchmark outputs -------")); @@ -1026,6 +1056,23 @@ void print_verilog_testbench_shared_ports( /* Add an empty line as splitter */ 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_check_flags( + std::fstream& fp, const AtomContext& atom_ctx, + const VprNetlistAnnotation& netlist_annotation, + const std::string& check_flag_port_postfix) { + /* Validate the file stream */ + valid_file_stream(fp); /* Instantiate register for output comparison */ print_verilog_comment( @@ -1054,6 +1101,44 @@ void print_verilog_testbench_shared_ports( 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 ModuleManager& module_manager, + const FabricGlobalPortInfo& global_ports, + const PinConstraints& pin_constraints, const AtomContext& atom_ctx, + const VprNetlistAnnotation& netlist_annotation, + const std::vector& clock_port_names, + const std::string& shared_input_port_postfix, + const std::string& benchmark_output_port_postfix, + const std::string& fpga_output_port_postfix, + const std::string& check_flag_port_postfix, const bool& no_self_checking) { + print_verilog_testbench_shared_input_ports( + fp, module_manager, global_ports, pin_constraints, atom_ctx, + netlist_annotation, clock_port_names, false, shared_input_port_postfix, + true); + + print_verilog_testbench_shared_fpga_output_ports( + fp, atom_ctx, netlist_annotation, fpga_output_port_postfix); + + if (no_self_checking) { + return; + } + + print_verilog_testbench_shared_benchmark_output_ports( + fp, atom_ctx, netlist_annotation, benchmark_output_port_postfix); + + print_verilog_testbench_shared_check_flags(fp, atom_ctx, netlist_annotation, + check_flag_port_postfix); +} + /******************************************************************** * Print signal initialization which * deposit initial values for the input ports of primitive circuit models diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.h b/openfpga/src/fpga_verilog/verilog_testbench_utils.h index 2aedd18e3..44850bb41 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.h +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.h @@ -38,7 +38,8 @@ void print_verilog_testbench_benchmark_instance( const std::string& module_input_port_postfix, const std::string& module_output_port_postfix, const std::string& input_port_postfix, const std::string& output_port_postfix, - const std::vector& clock_port_names, const AtomContext& atom_ctx, + const std::vector& clock_port_names, + const bool& include_clock_port_postfix, const AtomContext& atom_ctx, const VprNetlistAnnotation& netlist_annotation, const PinConstraints& pin_constraints, const BusGroup& bus_group, const bool& use_explicit_port_map); @@ -90,6 +91,30 @@ void print_verilog_testbench_random_stimuli( const std::string& check_flag_port_postfix, const std::vector& clock_ports, const bool& no_self_checking); +void print_verilog_testbench_shared_input_ports( + std::fstream& fp, const ModuleManager& module_manager, + const FabricGlobalPortInfo& global_ports, + const PinConstraints& pin_constraints, const AtomContext& atom_ctx, + const VprNetlistAnnotation& netlist_annotation, + const std::vector& clock_port_names, + const bool& include_clock_ports, const std::string& shared_input_port_postfix, + const bool& use_reg_port); + +void print_verilog_testbench_shared_fpga_output_ports( + std::fstream& fp, const AtomContext& atom_ctx, + const VprNetlistAnnotation& netlist_annotation, + const std::string& fpga_output_port_postfix); + +void print_verilog_testbench_shared_benchmark_output_ports( + std::fstream& fp, const AtomContext& atom_ctx, + const VprNetlistAnnotation& netlist_annotation, + const std::string& benchmark_output_port_postfix); + +void print_verilog_testbench_shared_check_flags( + std::fstream& fp, const AtomContext& atom_ctx, + const VprNetlistAnnotation& netlist_annotation, + const std::string& check_flag_port_postfix); + void print_verilog_testbench_shared_ports( std::fstream& fp, const ModuleManager& module_manager, const FabricGlobalPortInfo& global_ports, diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index b98a44007..02b77ad58 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -1146,7 +1146,7 @@ static void print_verilog_top_testbench_benchmark_instance( std::string(TOP_TESTBENCH_REFERENCE_INSTANCE_NAME), std::string(), std::string(), std::string(TOP_TESTBENCH_SHARED_INPUT_POSTFIX), std::string(TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX), clock_port_names, - atom_ctx, netlist_annotation, pin_constraints, bus_group, + false, atom_ctx, netlist_annotation, pin_constraints, bus_group, explicit_port_mapping); print_verilog_comment( diff --git a/openfpga_flow/openfpga_shell_scripts/mock_wrapper_example_script.openfpga b/openfpga_flow/openfpga_shell_scripts/mock_wrapper_example_script.openfpga new file mode 100644 index 000000000..feed9d0e7 --- /dev/null +++ b/openfpga_flow/openfpga_shell_scripts/mock_wrapper_example_script.openfpga @@ -0,0 +1,72 @@ +# Run VPR for the 'and' design +#--write_rr_graph example_rr_graph.xml +vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling ideal + +# Read OpenFPGA architecture definition +read_openfpga_arch -f ${OPENFPGA_ARCH_FILE} + +# Read OpenFPGA simulation settings +read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE} + +# Annotate the OpenFPGA architecture to VPR data base +# to debug use --verbose options +link_openfpga_arch --sort_gsb_chan_node_in_edges + +# Check and correct any naming conflicts in the BLIF netlist +check_netlist_naming_conflict --fix --report ./netlist_renaming.xml + +# Apply fix-up to Look-Up Table truth tables based on packing results +lut_truth_table_fixup + +# Build the module graph +# - Enabled compression on routing architecture modules +# - Enable pin duplication on grid modules +build_fabric --compress_routing #--verbose + +# Write the fabric hierarchy of module graph to a file +# This is used by hierarchical PnR flows +write_fabric_hierarchy --file ./fabric_hierarchy.txt + +# Repack the netlist to physical pbs +# This must be done before bitstream generator and testbench generation +# Strongly recommend it is done after all the fix-up have been applied +repack ${OPENFPGA_REPACK_DESIGN_CONSTRAINTS} #--verbose + +# Build the bitstream +# - Output the fabric-independent bitstream to a file +build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml + +# Build fabric-dependent bitstream +build_fabric_bitstream --verbose + +# Write fabric-dependent bitstream +write_fabric_bitstream --file fabric_bitstream.bit --format plain_text + +# Write the Verilog netlist for FPGA fabric +# - Enable the use of explicit port mapping in Verilog netlist +write_mock_fpga_wrapper --file ./SRC ${OPENFPGA_MOCK_WRAPPER_OPTIONS} ${OPENFPGA_MOCK_WRAPPER_BGF} ${OPENFPGA_MOCK_WRAPPER_PCF} + +# Write the Verilog testbench for FPGA fabric +# - We suggest the use of same output directory as fabric Verilog netlists +# - Must specify the reference benchmark file if you want to output any testbenches +# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA +# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase +# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts +write_preconfigured_fabric_wrapper --embed_bitstream none --file ./SRC --explicit_port_mapping ${OPENFPGA_MOCK_WRAPPER_BGF} ${OPENFPGA_MOCK_WRAPPER_PCF} +write_preconfigured_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --explicit_port_mapping ${OPENFPGA_MOCK_WRAPPER_BGF} ${OPENFPGA_MOCK_WRAPPER_PCF} + +# Write the SDC files for PnR backend +# - Turn on every options here +write_pnr_sdc --file ./SDC + +# Write SDC to disable timing for configure ports +write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc + +# Write the SDC to run timing analysis for a mapped FPGA fabric +write_analysis_sdc --file ./SDC_analysis + +# Finish and exit OpenFPGA +exit + +# Note : +# To run verification at the end of the flow maintain source in ./SRC directory diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh index 6b2d013cb..489120590 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -115,6 +115,12 @@ run-task basic_tests/fabric_key/load_external_key_qlbanksr_multi_chain_fpga $@ # TODO: This feature is temporarily out of test due to the emergency in delivering netlists for multi-chain shift-register memory bank #run-task basic_tests/fabric_key/load_external_key_multi_region_qlbanksr_fpga $@ +echo -e "Testing mock wrapper" +run-task basic_tests/mock_wrapper/mock_wrapper_explicit_port_mapping $@ +run-task basic_tests/mock_wrapper/mock_wrapper_implicit_port_mapping $@ +run-task basic_tests/mock_wrapper/mock_wrapper_pcf $@ +run-task basic_tests/mock_wrapper/mock_wrapper_bgf $@ + echo -e "Testing K4 series FPGA"; echo -e "Testing K4N4 with facturable LUTs"; run-task basic_tests/k4_series/k4n4_frac_lut $@ diff --git a/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_bgf/config/counter8_bus_group.xml b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_bgf/config/counter8_bus_group.xml new file mode 100644 index 000000000..a0fd22f77 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_bgf/config/counter8_bus_group.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_bgf/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_bgf/config/pin_constraints_reset.xml new file mode 100644 index 000000000..abcf209f6 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_bgf/config/pin_constraints_reset.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_bgf/config/task.conf b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_bgf/config/task.conf new file mode 100644 index 000000000..1b5e4a371 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_bgf/config/task.conf @@ -0,0 +1,51 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# 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] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = false +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/mock_wrapper_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_repack_design_constraints= +openfpga_mock_wrapper_options=--explicit_port_mapping +openfpga_mock_wrapper_bgf= +openfpga_mock_wrapper_pcf= + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v + +[SYNTHESIS_PARAM] +# Yosys script parameters +bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_cell_sim.v +bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_dff_map.v +bench_yosys_bram_map_rules_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram.txt +bench_yosys_bram_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram_map.v +bench_yosys_dsp_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_dsp_map.v +bench_yosys_dsp_map_parameters_common=-D DSP_A_MAXWIDTH=36 -D DSP_B_MAXWIDTH=36 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=mult_36x36 +bench_read_verilog_options_common = -nolatches +bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys +bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys + +bench0_top = counter +bench0_openfpga_mock_wrapper_pcf=-pcf ${PATH:TASK_DIR}/config/pin_constraints_reset.xml +bench0_openfpga_mock_wrapper_bgf=-bgf ${PATH:TASK_DIR}/config/counter8_bus_group.xml + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= diff --git a/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_explicit_port_mapping/config/task.conf b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_explicit_port_mapping/config/task.conf new file mode 100644 index 000000000..ce8a09b7f --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_explicit_port_mapping/config/task.conf @@ -0,0 +1,45 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# 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] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = false +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/mock_wrapper_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_repack_design_constraints= +openfpga_mock_wrapper_options=--explicit_port_mapping +openfpga_mock_wrapper_bgf= +openfpga_mock_wrapper_pcf= + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v +bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v +bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v + +[SYNTHESIS_PARAM] +bench_read_verilog_options_common = -nolatches +bench0_top = and2 + +bench1_top = or2 + +bench2_top = and2_latch + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= diff --git a/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_implicit_port_mapping/config/task.conf b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_implicit_port_mapping/config/task.conf new file mode 100644 index 000000000..6e6d87b9f --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_implicit_port_mapping/config/task.conf @@ -0,0 +1,45 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# 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] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = false +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/mock_wrapper_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_repack_design_constraints= +openfpga_mock_wrapper_options= +openfpga_mock_wrapper_bgf= +openfpga_mock_wrapper_pcf= + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v +bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v +bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v + +[SYNTHESIS_PARAM] +bench_read_verilog_options_common = -nolatches +bench0_top = and2 + +bench1_top = or2 + +bench2_top = and2_latch + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= diff --git a/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_pcf/config/and2_latch_pin_constraints.xml b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_pcf/config/and2_latch_pin_constraints.xml new file mode 100644 index 000000000..e6949c9d4 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_pcf/config/and2_latch_pin_constraints.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_pcf/config/repack_pin_constraints.xml b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_pcf/config/repack_pin_constraints.xml new file mode 100644 index 000000000..d695cf85e --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_pcf/config/repack_pin_constraints.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_pcf/config/task.conf b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_pcf/config/task.conf new file mode 100644 index 000000000..3352a51bf --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/mock_wrapper/mock_wrapper_pcf/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] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = false +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/mock_wrapper_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTile4Clk_cc_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_4clock_sim_openfpga.xml +openfpga_repack_design_constraints=--design_constraints ${PATH:TASK_DIR}/config/repack_pin_constraints.xml +openfpga_mock_wrapper_options= +openfpga_mock_wrapper_bgf= +openfpga_mock_wrapper_pcf= + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTile4Clk_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch_2clock/and2_latch_2clock.v + +[SYNTHESIS_PARAM] +bench_read_verilog_options_common = -nolatches + +bench0_top = and2_latch_2clock +bench0_openfpga_pin_constraints=--design_constraints ${PATH:TASK_DIR}/config/and2_latch_pin_constraints.xml +bench0_openfpga_mock_wrapper_pcf=-pcf ${PATH:TASK_DIR}/config/and2_latch_pin_constraints.xml +bench0_openfpga_mock_wrapper_bgf= + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist=