diff --git a/docs/source/manual/file_formats/index.rst b/docs/source/manual/file_formats/index.rst index e873286fd..340bb3d8a 100644 --- a/docs/source/manual/file_formats/index.rst +++ b/docs/source/manual/file_formats/index.rst @@ -45,3 +45,5 @@ OpenFPGA widely uses XML format for interchangeable files fabric_pin_physical_location_file fabric_hierarchy_file + + reference_file diff --git a/docs/source/manual/file_formats/reference_file.rst b/docs/source/manual/file_formats/reference_file.rst new file mode 100644 index 000000000..f2240df62 --- /dev/null +++ b/docs/source/manual/file_formats/reference_file.rst @@ -0,0 +1,80 @@ +.. _file_format_reference_file: + +Reference File (.yaml) +---------------------------------------- + +This file is generated by command :ref:`openfpga_setup_commands_report_reference` + + +The reference file aims to the show reference number of each child module of given parent module + +By using the options of the command :ref:`openfpga_setup_commands_report_reference`, user can selectively output the reference info under the given parent module on their needs. + +An example of the file is shown as follows. + +.. code-block:: yaml + +Date: Mon Sep 9 16:41:53 2024 + +#the instance names are given during netlist generation +references: +- module: grid_io_top + count: 1 + instances: + - grid_io_top_1__2_ +- module: grid_io_right + count: 1 + instances: + - grid_io_right_2__1_ +- module: grid_io_bottom + count: 1 + instances: + - grid_io_bottom_1__0_ +- module: grid_io_left + count: 1 + instances: + - grid_io_left_0__1_ +- module: grid_clb + count: 1 + instances: + - grid_clb_1__1_ +- module: sb_0__0_ + count: 1 + instances: + - sb_0__0_ +- module: sb_0__1_ + count: 1 + instances: + - sb_0__1_ +- module: sb_1__0_ + count: 1 + instances: + - sb_1__0_ +- module: sb_1__1_ + count: 1 + instances: + - sb_1__1_ +- module: cbx_1__0_ + count: 1 + instances: + - cbx_1__0_ +- module: cbx_1__1_ + count: 1 + instances: + - cbx_1__1_ +- module: cby_0__1_ + count: 1 + instances: + - cby_0__1_ +- module: cby_1__1_ + count: 1 + instances: + - cby_1__1_ + direct_interc + +In this example, the parent module is ``fpga_top``. +The child modules under ``fpga_top`` are ``grid_io_top``, ``grid_io_right``, and etc. + +The instance of the child module ``grid_io_top`` is shown as a list as below: + - grid_io_top_1__2_ + diff --git a/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst b/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst index d5fce4b8f..b2e10d1b6 100644 --- a/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst +++ b/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst @@ -525,3 +525,26 @@ write_fabric_pin_physical_location .. option:: --verbose Show verbose log + +.. _openfpga_setup_commands_report_reference: + +report_reference +~~~~~~~~~~~~~~~~~~~~ + + Write reference information of each child module under a given parent module to a YAML file + + .. option:: --file or -f + + Specify the file name to write the reference information + + .. option:: --module + + Specify the parent module name, under which the references of each child module will be reported. + + .. option:: --no_time_stamp + + Do not print time stamp in output files + + .. option:: --verbose + + Show verbose info \ No newline at end of file diff --git a/openfpga/src/base/openfpga_build_fabric_template.h b/openfpga/src/base/openfpga_build_fabric_template.h index b36903a22..bf1a292fa 100644 --- a/openfpga/src/base/openfpga_build_fabric_template.h +++ b/openfpga/src/base/openfpga_build_fabric_template.h @@ -21,6 +21,7 @@ #include "read_xml_module_name_map.h" #include "read_xml_tile_config.h" #include "rename_modules.h" +#include "report_reference.h" #include "vtr_log.h" #include "vtr_time.h" #include "write_xml_fabric_pin_physical_location.h" @@ -472,6 +473,38 @@ int write_fabric_pin_physical_location_template( cmd_context.option_enable(cmd, opt_verbose)); } +/******************************************************************** + * Report reference to a file + *******************************************************************/ +template +int report_reference_template(const T& openfpga_ctx, const Command& cmd, + const CommandContext& cmd_context) { + CommandOptionId opt_verbose = cmd.option("verbose"); + CommandOptionId opt_no_time_stamp = cmd.option("no_time_stamp"); + + /* Check the option '--file' is enabled or not + * Actually, it must be enabled as the shell interface will check + * before reaching this fuction + */ + CommandOptionId opt_file = cmd.option("file"); + VTR_ASSERT(true == cmd_context.option_enable(cmd, opt_file)); + VTR_ASSERT(false == cmd_context.option_value(cmd, opt_file).empty()); + + std::string file_name = cmd_context.option_value(cmd, opt_file); + + std::string module_name("*"); /* Use a wildcard for everything */ + CommandOptionId opt_module = cmd.option("module"); + if (true == cmd_context.option_enable(cmd, opt_module)) { + module_name = cmd_context.option_value(cmd, opt_module); + } + + /* Write hierarchy to a file */ + return report_reference(file_name.c_str(), module_name, + openfpga_ctx.module_graph(), + !cmd_context.option_enable(cmd, opt_no_time_stamp), + cmd_context.option_enable(cmd, opt_verbose)); +} + } /* end namespace openfpga */ #endif diff --git a/openfpga/src/base/openfpga_setup_command_template.h b/openfpga/src/base/openfpga_setup_command_template.h index 1d74a61f0..4353f37c1 100644 --- a/openfpga/src/base/openfpga_setup_command_template.h +++ b/openfpga/src/base/openfpga_setup_command_template.h @@ -937,6 +937,51 @@ ShellCommandId add_write_fabric_pin_physical_location_command_template( return shell_cmd_id; } +/******************************************************************** + * - Add a command to Shell environment: report_reference + * - Add associated options + * - Add command dependency + *******************************************************************/ +template +ShellCommandId add_report_reference_command_template( + openfpga::Shell& shell, const ShellCommandClassId& cmd_class_id, + const std::vector& dependent_cmds, const bool& hidden) { + Command shell_cmd("report_reference"); + /* Add an option '--file' in short '-f'*/ + CommandOptionId opt_file = + shell_cmd.add_option("file", true, "specify the file to output results"); + shell_cmd.set_option_short_name(opt_file, "f"); + shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING); + + /* Add an option '--module'*/ + CommandOptionId opt_module = + shell_cmd.add_option("module", false, + "specify the module under which the references of " + "child modules will be reported"); + shell_cmd.set_option_require_value(opt_module, openfpga::OPT_STRING); + + /* Add an option '--no_time_stamp' */ + shell_cmd.add_option("no_time_stamp", false, + "do not print time stamp in output files"); + + shell_cmd.add_option("verbose", false, "Show verbose outputs"); + + /* Add command to the Shell */ + ShellCommandId shell_cmd_id = + shell.add_command(shell_cmd, + "report all instances of each unique module, " + "under a given module", + hidden); + shell.set_command_class(shell_cmd_id, cmd_class_id); + shell.set_command_const_execute_function(shell_cmd_id, + report_reference_template); + + /* Add command dependency to the Shell */ + shell.set_command_dependency(shell_cmd_id, dependent_cmds); + + return shell_cmd_id; +} + template void add_setup_command_templates(openfpga::Shell& shell, const bool& hidden = false) { @@ -1188,6 +1233,15 @@ void add_setup_command_templates(openfpga::Shell& shell, add_write_fabric_pin_physical_location_command_template( shell, openfpga_setup_cmd_class, cmd_dependency_write_fabric_pin_physical_location, hidden); + + /******************************** + * Command 'report_reference' + */ + /* The command should NOT be executed before 'build_fabric' */ + std::vector cmd_dependency_report_reference; + cmd_dependency_report_reference.push_back(build_fabric_cmd_id); + add_report_reference_command_template( + shell, openfpga_setup_cmd_class, cmd_dependency_report_reference, hidden); } } /* end namespace openfpga */ diff --git a/openfpga/src/utils/report_reference.cpp b/openfpga/src/utils/report_reference.cpp new file mode 100644 index 000000000..3a3bea935 --- /dev/null +++ b/openfpga/src/utils/report_reference.cpp @@ -0,0 +1,123 @@ +/*************************************************************************************** + * Output internal structure of module graph to XML format + ***************************************************************************************/ +/* Headers from system goes first */ +#include +#include +#include +#include +#include + +/* Headers from vtrutil library */ +#include "vtr_assert.h" +#include "vtr_log.h" +#include "vtr_time.h" + +/* Headers from openfpgautil library */ +#include "command_exit_codes.h" +#include "openfpga_digest.h" +#include "openfpga_naming.h" +#include "report_reference.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/******************************************************************** + * Top-level function + *******************************************************************/ +int report_reference(const char* fname, const std::string& module_name, + const ModuleManager& module_manager, + const bool& include_time_stamp, const bool& verbose) { + vtr::ScopedStartFinishTimer timer("Report reference"); + + ModuleId parent_module = module_manager.find_module(module_name); + if (false == module_manager.valid_module_id(parent_module)) { + VTR_LOG_ERROR("Module %s doesn't exist\n", module_name.c_str()); + return CMD_EXEC_FATAL_ERROR; + } + + show_reference_count(parent_module, module_manager); + + return write_reference_to_file(fname, parent_module, module_manager, + include_time_stamp, verbose); +} + +/******************************************************************** + * show reference count of each child module under given parent module + *******************************************************************/ +void show_reference_count(const ModuleId& parent_module, + const ModuleManager& module_manager) { + VTR_LOG( + "----------------------------------------------------------------------\n"); + VTR_LOG( + "Module Count \n"); + VTR_LOG( + "--------------------------------------------------------------------- \n"); + size_t ref_cnt = 0; + for (ModuleId child_module : module_manager.child_modules(parent_module)) { + std::string child_module_name = module_manager.module_name(child_module); + std::vector child_inst_vec = + module_manager.child_module_instances(parent_module, child_module); + VTR_LOG("%-s %d\n", child_module_name.c_str(), child_inst_vec.size()); + ref_cnt += child_inst_vec.size(); + } + VTR_LOG( + "----------------------------------------------------------------------\n"); + VTR_LOG("Total: %zu modules %zu references\n", + module_manager.child_modules(parent_module).size(), ref_cnt); + VTR_LOG( + "----------------------------------------------------------------------\n"); +} + +/******************************************************************** + * write reference info to a given file in YAML format + *******************************************************************/ +int write_reference_to_file(const char* fname, const ModuleId& parent_module, + const ModuleManager& module_manager, + const bool& include_time_stamp, + const bool& verbose) { + std::fstream fp; + fp.open(std::string(fname), std::fstream::out | std::fstream::trunc); + openfpga::check_file_stream(fname, fp); + + if (include_time_stamp) { + auto end = std::chrono::system_clock::now(); + std::time_t end_time = std::chrono::system_clock::to_time_t(end); + fp << "Date: " << std::ctime(&end_time) << std::endl; + } + + fp << "#the instance names are given during netlist generation" << std::endl; + + size_t ref_cnt = 0; + fp << "references:" << std::endl; + for (ModuleId child_module : module_manager.child_modules(parent_module)) { + std::string child_module_name = module_manager.module_name(child_module); + std::vector child_inst_vec = + module_manager.child_module_instances(parent_module, child_module); + fp << "- module: " << child_module_name.c_str() << std::endl + << " count: " << child_inst_vec.size() << std::endl + << " instances:" << std::endl; + for (size_t inst_id : child_inst_vec) { + std::string inst_name = + module_manager.instance_name(parent_module, child_module, inst_id); + fp << " - "; + if (true == inst_name.empty()) { + fp << generate_instance_name(child_module_name, inst_id) << std::endl; + } else { + fp << inst_name << std::endl; + } + } + ref_cnt += child_inst_vec.size(); + } + + if (verbose) { + fp << std::endl + << "Total: " << module_manager.child_modules(parent_module).size() + << " modules " << ref_cnt << " references" << std::endl; + } + + fp.close(); + return CMD_EXEC_SUCCESS; +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/utils/report_reference.h b/openfpga/src/utils/report_reference.h new file mode 100644 index 000000000..2afd89cc0 --- /dev/null +++ b/openfpga/src/utils/report_reference.h @@ -0,0 +1,30 @@ +#ifndef REPORT_REFERENCE_H +#define REPORT_REFERENCE_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include + +#include "module_manager.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { +int report_reference(const char* fname, const std::string& module_name, + const ModuleManager& module_manager, + const bool& include_time_stamp, const bool& verbose); + +void show_reference_count(const ModuleId& parent_module, + const ModuleManager& module_manager); + +int write_reference_to_file(const char* fname, const ModuleId& parent_module, + const ModuleManager& module_manager, + const bool& include_time_stamp, + const bool& verbose); +} /* end namespace openfpga */ + +#endif diff --git a/openfpga_flow/openfpga_shell_scripts/report_reference_example_script.openfpga b/openfpga_flow/openfpga_shell_scripts/report_reference_example_script.openfpga new file mode 100644 index 000000000..f7e4d4f10 --- /dev/null +++ b/openfpga_flow/openfpga_shell_scripts/report_reference_example_script.openfpga @@ -0,0 +1,37 @@ +# Run VPR for the 'and' design +#--write_rr_graph example_rr_graph.xml +vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route --absorb_buffer_luts off + +# 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 --activity_file ${ACTIVITY_FILE} --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 +# - Enabled frame view creation to save runtime and memory +# Note that this is turned on when bitstream generation +# is the ONLY purpose of the flow!!! +build_fabric --compress_routing --frame_view #--verbose + +# Report reference to a file +report_reference ${OPENFPGA_REPORT_REFERENCE_MODULE_OPTIONS} +report_reference ${OPENFPGA_REPORT_REFERENCE_VERBOSE_OPTIONS} +report_reference ${OPENFPGA_REPORT_REFERENCE_NO_TIME_STAMP_OPTIONS} + +# 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 6b17c21c6..0d9f1e2d8 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -315,6 +315,10 @@ run-task basic_tests/no_time_stamp/device_1x1 $@ run-task basic_tests/no_time_stamp/device_4x4 $@ run-task basic_tests/no_time_stamp/no_cout_in_gsb $@ run-task basic_tests/no_time_stamp/dump_waveform $@ + +echo -e "Testing report reference to file"; +run-task basic_tests/report_reference $@ + # Run git-diff to ensure no changes on the golden netlists # Switch to root path in case users are running the tests in another location cd ${OPENFPGA_PATH} diff --git a/openfpga_flow/tasks/basic_tests/report_reference/config/task.conf b/openfpga_flow/tasks/basic_tests/report_reference/config/task.conf new file mode 100644 index 000000000..0fa9feefd --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/report_reference/config/task.conf @@ -0,0 +1,36 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# 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 = true +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/report_reference_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_40nm_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml +openfpga_report_reference_module_options=--file reference_module.yaml --module fpga_top +openfpga_report_reference_verbose_options=--file reference_verbose.yaml --module fpga_top --verbose +openfpga_report_reference_no_time_stamp_options=--file reference_no_time_stamp.yaml --module grid_io_right --no_time_stamp + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v + +[SYNTHESIS_PARAM] +bench_read_verilog_options_common = -nolatches +bench0_top = and2 + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]