diff --git a/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp b/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp index 3ae2083df..00cbbe1e3 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp +++ b/libopenfpga/libopenfpgautil/src/openfpga_digest.cpp @@ -235,4 +235,20 @@ void create_directory(const std::string& dir_path, const bool& recursive) { } } +/******************************************************************** + * Write a number of space to a file + ********************************************************************/ +bool write_space_to_file(std::fstream& fp, + const size_t& num_space) { + if (false == valid_file_stream(fp)) { + return false; + } + + for (size_t i = 0; i < num_space; ++i) { + fp << " "; + } + + return true; +} + } /* namespace openfpga ends */ diff --git a/libopenfpga/libopenfpgautil/src/openfpga_digest.h b/libopenfpga/libopenfpgautil/src/openfpga_digest.h index 0e1cd5d76..a28b2c4d0 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_digest.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_digest.h @@ -25,6 +25,9 @@ std::string find_path_dir_name(const std::string& file_name); void create_directory(const std::string& dir_path, const bool& recursive = true); +bool write_space_to_file(std::fstream& fp, + const size_t& num_space); + } /* namespace openfpga ends */ #endif diff --git a/openfpga/src/base/openfpga_build_fabric.cpp b/openfpga/src/base/openfpga_build_fabric.cpp index 67203216a..e013ab267 100644 --- a/openfpga/src/base/openfpga_build_fabric.cpp +++ b/openfpga/src/base/openfpga_build_fabric.cpp @@ -11,6 +11,7 @@ #include "device_rr_gsb.h" #include "device_rr_gsb_utils.h" #include "build_device_module.h" +#include "fabric_hierarchy_writer.h" #include "openfpga_build_fabric.h" /* Include global variables of VPR */ @@ -85,4 +86,28 @@ int build_fabric(OpenfpgaContext& openfpga_ctx, return CMD_EXEC_SUCCESS; } +/******************************************************************** + * Build the module graph for FPGA device + *******************************************************************/ +int write_fabric_hierarchy(const OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context) { + + CommandOptionId opt_verbose = cmd.option("verbose"); + + /* 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 hie_file_name = cmd_context.option_value(cmd, opt_file); + + /* Write hierarchy to a file */ + return write_fabric_hierarchy_to_text_file(openfpga_ctx.module_graph(), + hie_file_name, + cmd_context.option_enable(cmd, opt_verbose)); +} + } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_build_fabric.h b/openfpga/src/base/openfpga_build_fabric.h index 3b63c7ab2..6a090397d 100644 --- a/openfpga/src/base/openfpga_build_fabric.h +++ b/openfpga/src/base/openfpga_build_fabric.h @@ -18,6 +18,9 @@ namespace openfpga { int build_fabric(OpenfpgaContext& openfpga_ctx, const Command& cmd, const CommandContext& cmd_context); +int write_fabric_hierarchy(const OpenfpgaContext& openfpga_ctx, + const Command& cmd, const CommandContext& cmd_context); + } /* end namespace openfpga */ #endif diff --git a/openfpga/src/base/openfpga_setup_command.cpp b/openfpga/src/base/openfpga_setup_command.cpp index 8f4b0cec3..2a3b11227 100644 --- a/openfpga/src/base/openfpga_setup_command.cpp +++ b/openfpga/src/base/openfpga_setup_command.cpp @@ -238,6 +238,37 @@ ShellCommandId add_openfpga_build_fabric_command(openfpga::Shell& shell, + const ShellCommandClassId& cmd_class_id, + const std::vector& dependent_cmds) { + + Command shell_cmd("write_fabric_hierarchy"); + + /* Add an option '--file' */ + CommandOptionId opt_file = shell_cmd.add_option("file", true, "Specify the file name to write the hierarchy to"); + shell_cmd.set_option_short_name(opt_file, "f"); + shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING); + + /* Add an option '--verbose' */ + shell_cmd.add_option("verbose", false, "Show verbose outputs"); + + /* Add command 'write_fabric_hierarchy' to the Shell */ + ShellCommandId shell_cmd_id = shell.add_command(shell_cmd, "Write the hierarchy of FPGA fabric graph to a plain-text file"); + shell.set_command_class(shell_cmd_id, cmd_class_id); + shell.set_command_const_execute_function(shell_cmd_id, write_fabric_hierarchy); + + /* Add command dependency to the Shell */ + shell.set_command_dependency(shell_cmd_id, dependent_cmds); + + return shell_cmd_id; +} + void add_openfpga_setup_commands(openfpga::Shell& shell) { /* Get the unique id of 'vpr' command which is to be used in creating the dependency graph */ const ShellCommandId& vpr_cmd_id = shell.command(std::string("vpr")); @@ -317,9 +348,19 @@ void add_openfpga_setup_commands(openfpga::Shell& shell) { /* The 'build_fabric' command should NOT be executed before 'link_openfpga_arch' */ std::vector build_fabric_dependent_cmds; build_fabric_dependent_cmds.push_back(link_arch_cmd_id); - add_openfpga_build_fabric_command(shell, - openfpga_setup_cmd_class, - build_fabric_dependent_cmds); + ShellCommandId build_fabric_cmd_id = add_openfpga_build_fabric_command(shell, + openfpga_setup_cmd_class, + build_fabric_dependent_cmds); + + /******************************** + * Command 'write_fabric_hierarchy' + */ + /* The 'write_fabric_hierarchy' command should NOT be executed before 'build_fabric' */ + std::vector write_fabric_hie_dependent_cmds; + write_fabric_hie_dependent_cmds.push_back(build_fabric_cmd_id); + add_openfpga_write_fabric_hierarchy_command(shell, + openfpga_setup_cmd_class, + write_fabric_hie_dependent_cmds); } } /* end namespace openfpga */ diff --git a/openfpga/src/fabric/fabric_hierarchy_writer.cpp b/openfpga/src/fabric/fabric_hierarchy_writer.cpp new file mode 100644 index 000000000..7b752f015 --- /dev/null +++ b/openfpga/src/fabric/fabric_hierarchy_writer.cpp @@ -0,0 +1,129 @@ +/*************************************************************************************** + * Output internal structure of Module Graph hierarchy to file formats + ***************************************************************************************/ +/* Headers from vtrutil library */ +#include "vtr_log.h" +#include "vtr_assert.h" +#include "vtr_time.h" + +/* Headers from openfpgautil library */ +#include "openfpga_digest.h" + +#include "openfpga_naming.h" + +#include "fabric_hierarchy_writer.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/*************************************************************************************** + * Recursively output child module of the parent_module to a text file + * We use Depth-First Search (DFS) here so that we can output a tree down to leaf first + * Add space (indent) based on the depth in hierarchy + * e.g. depth = 1 means a space as indent + ***************************************************************************************/ +static +int rec_output_module_hierarchy_to_text_file(std::fstream& fp, + const size_t& hie_depth, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const bool& verbose) { + if (false == valid_file_stream(fp)) { + return 2; + } + + /* Iterate over all the child module */ + for (const ModuleId& child_module : module_manager.child_modules(parent_module)) { + if (false == write_space_to_file(fp, hie_depth)) { + return 2; + } + + if (true != module_manager.valid_module_id(child_module)) { + VTR_LOGV_ERROR(verbose, + "Unable to find the child module '%u'!\n", + size_t(child_module)); + return 1; + } + + fp << module_manager.module_name(child_module); + fp << "\n"; + + /* Go to next level */ + int status = rec_output_module_hierarchy_to_text_file(fp, + hie_depth + 1, /* Increment the depth for the next level */ + module_manager, + child_module, + verbose); + if (0 != status) { + return status; + } + } + + return 0; +} + +/*************************************************************************************** + * Write the hierarchy of modules to a plain text file + * e.g., + * + * + * ... + * This file is mainly used by hierarchical P&R flow + * + * Return 0 if successful + * Return 1 if there are more serious bugs in the architecture + * Return 2 if fail when creating files + ***************************************************************************************/ +int write_fabric_hierarchy_to_text_file(const ModuleManager& module_manager, + const std::string& fname, + const bool& verbose) { + std::string timer_message = std::string("Write fabric hierarchy to plain-text file '") + fname + std::string("'"); + + std::string dir_path = format_dir_path(find_path_dir_name(fname)); + + /* Create directories */ + create_directory(dir_path); + + /* Start time count */ + vtr::ScopedStartFinishTimer timer(timer_message); + + /* Use default name if user does not provide one */ + VTR_ASSERT(true != fname.empty()); + + /* Create a file handler*/ + std::fstream fp; + /* Open a file */ + fp.open(fname, std::fstream::out | std::fstream::trunc); + + /* Validate the file stream */ + check_file_stream(fname.c_str(), fp); + + /* Find top-level module */ + std::string top_module_name = generate_fpga_top_module_name(); + ModuleId top_module = module_manager.find_module(top_module_name); + if (true != module_manager.valid_module_id(top_module)) { + VTR_LOGV_ERROR(verbose, + "Unable to find the top-level module '%s'!\n", + top_module_name.c_str()); + return 1; + } + + /* Record current depth of module: top module is the root with 0 depth */ + size_t hie_depth = 0; + + fp << top_module_name << "\n"; + + /* Visit child module recursively and output the hierarchy */ + int err_code = rec_output_module_hierarchy_to_text_file(fp, + hie_depth + 1, /* Start with level 1 */ + module_manager, + top_module, + verbose); + + /* close a file */ + fp.close(); + + return err_code; +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/fabric/fabric_hierarchy_writer.h b/openfpga/src/fabric/fabric_hierarchy_writer.h new file mode 100644 index 000000000..48e112c76 --- /dev/null +++ b/openfpga/src/fabric/fabric_hierarchy_writer.h @@ -0,0 +1,23 @@ +#ifndef FABRIC_HIERARCHY_WRITER_H +#define FABRIC_HIERARCHY_WRITER_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include "vpr_context.h" +#include "openfpga_context.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +int write_fabric_hierarchy_to_text_file(const ModuleManager& module_manager, + const std::string& fname, + const bool& verbose); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/test_script/and_k6_frac.openfpga b/openfpga/test_script/and_k6_frac.openfpga index 20a75a661..014142fb1 100644 --- a/openfpga/test_script/and_k6_frac.openfpga +++ b/openfpga/test_script/and_k6_frac.openfpga @@ -24,6 +24,8 @@ lut_truth_table_fixup #--verbose # - Enable pin duplication on grid modules build_fabric --compress_routing --duplicate_grid_pin #--verbose +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