diff --git a/libs/libopenfpgautil/src/openfpga_reserved_words.h b/libs/libopenfpgautil/src/openfpga_reserved_words.h index 05d1e2d2e..11dd44ef0 100644 --- a/libs/libopenfpgautil/src/openfpga_reserved_words.h +++ b/libs/libopenfpgautil/src/openfpga_reserved_words.h @@ -12,6 +12,8 @@ namespace openfpga { /* Top-level module name */ constexpr const char* FPGA_TOP_MODULE_NAME = "fpga_top"; +constexpr const char* FPGA_CORE_MODULE_NAME = "fpga_core"; +constexpr const char* FPGA_CORE_INSTANCE_NAME = "fpga_instance"; /* Configuration chain naming constant strings */ constexpr const char* CONFIGURABLE_MEMORY_CHAIN_IN_NAME = "ccff_head"; diff --git a/openfpga/src/base/openfpga_build_fabric_template.h b/openfpga/src/base/openfpga_build_fabric_template.h index 065f421d0..e025b2a03 100644 --- a/openfpga/src/base/openfpga_build_fabric_template.h +++ b/openfpga/src/base/openfpga_build_fabric_template.h @@ -14,6 +14,7 @@ #include "fabric_hierarchy_writer.h" #include "fabric_key_writer.h" #include "globals.h" +#include "openfpga_naming.h" #include "read_xml_fabric_key.h" #include "vtr_log.h" #include "vtr_time.h" @@ -237,10 +238,20 @@ int write_fabric_io_info_template(const T& openfpga_ctx, const Command& cmd, template int add_fpga_core_to_fabric_template(T& openfpga_ctx, const Command& cmd, const CommandContext& cmd_context) { + CommandOptionId opt_frame_view = cmd.option("frame_view"); + bool frame_view = cmd_context.option_enable(cmd, opt_frame_view); CommandOptionId opt_verbose = cmd.option("verbose"); bool verbose_output = cmd_context.option_enable(cmd, opt_verbose); - return add_fpga_core_to_device_module_graph(openfpga_ctx.mutable_module_graph(), verbose_output); + CommandOptionId opt_inst_name = cmd.option("instance_name"); + std::string core_inst_name = generate_fpga_core_instance_name(); + if (true == cmd_context.option_enable(cmd, opt_inst_name)) { + core_inst_name = cmd_context.option_value(cmd, opt_inst_name); + } + + return add_fpga_core_to_device_module_graph( + openfpga_ctx.mutable_module_graph(), core_inst_name, frame_view, + verbose_output); } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp index 38dabf0e8..13eabe4b1 100644 --- a/openfpga/src/base/openfpga_naming.cpp +++ b/openfpga/src/base/openfpga_naming.cpp @@ -1399,6 +1399,22 @@ std::string generate_fpga_top_module_name() { return std::string(FPGA_TOP_MODULE_NAME); } +/********************************************************************* + * Generate the module name for the fpga core module + * We give a fixed name here, because it is independent from benchmark file + ********************************************************************/ +std::string generate_fpga_core_module_name() { + return std::string(FPGA_CORE_MODULE_NAME); +} + +/********************************************************************* + * Generate the module name for the fpga core module + * We give a fixed name here, because it is independent from benchmark file + ********************************************************************/ +std::string generate_fpga_core_instance_name() { + return std::string(FPGA_CORE_INSTANCE_NAME); +} + /********************************************************************* * Generate the netlist name for the top-level module * The top-level module is actually the FPGA fabric diff --git a/openfpga/src/base/openfpga_naming.h b/openfpga/src/base/openfpga_naming.h index 8e6fb631a..3400406c8 100644 --- a/openfpga/src/base/openfpga_naming.h +++ b/openfpga/src/base/openfpga_naming.h @@ -258,6 +258,10 @@ std::string generate_fpga_global_io_port_name( std::string generate_fpga_top_module_name(); +std::string generate_fpga_core_module_name(); + +std::string generate_fpga_core_instance_name(); + std::string generate_fpga_top_netlist_name(const std::string& postfix); std::string generate_const_value_module_name(const size_t& const_val); diff --git a/openfpga/src/base/openfpga_setup_command_template.h b/openfpga/src/base/openfpga_setup_command_template.h index 9a3498d32..2c8e38de5 100644 --- a/openfpga/src/base/openfpga_setup_command_template.h +++ b/openfpga/src/base/openfpga_setup_command_template.h @@ -703,13 +703,25 @@ ShellCommandId add_add_fpga_core_to_fabric_command_template( const std::vector& dependent_cmds, const bool& hidden) { Command shell_cmd("add_fpga_core_to_fabric"); + /* Add an option '--instance_name'*/ + CommandOptionId opt_inst_name = shell_cmd.add_option( + "instance_name", false, "specify the instance of fpga_core under fpga_top"); + shell_cmd.set_option_require_value(opt_inst_name, openfpga::OPT_STRING); + + /* Add an option '--verbose' */ + shell_cmd.add_option( + "frame_view", false, + "Build only frame view of the fabric (nets are skipped)"); /* Add an option '--verbose' */ shell_cmd.add_option("verbose", false, "Show verbose outputs"); /* Add command 'pb_pin_fixup' to the Shell */ ShellCommandId shell_cmd_id = shell.add_command( shell_cmd, - "Add fpga_core as an intermediate layer to FPGA fabric. After this command, the fpga_top will remain the top-level module while there is a new module fpga_core under it. Under fpga_core, there will be the detailed building blocks", + "Add fpga_core as an intermediate layer to FPGA fabric. After this " + "command, the fpga_top will remain the top-level module while there is a " + "new module fpga_core under it. Under fpga_core, there will be the " + "detailed building blocks", hidden); shell.set_command_class(shell_cmd_id, cmd_class_id); shell.set_command_execute_function(shell_cmd_id, @@ -906,8 +918,10 @@ void add_setup_command_templates(openfpga::Shell& shell, * 'build_fabric' */ std::vector add_fpga_core_to_fabric_dependent_cmds; add_fpga_core_to_fabric_dependent_cmds.push_back(build_fabric_cmd_id); - ShellCommandId add_fpga_core_to_fabric_cmd_id = add_add_fpga_core_to_fabric_command_template( - shell, openfpga_setup_cmd_class, add_fpga_core_to_fabric_dependent_cmds, hidden); + ShellCommandId add_fpga_core_to_fabric_cmd_id = + add_add_fpga_core_to_fabric_command_template( + shell, openfpga_setup_cmd_class, add_fpga_core_to_fabric_dependent_cmds, + hidden); /******************************** * Command 'write_fabric_hierarchy' diff --git a/openfpga/src/fabric/build_device_module.cpp b/openfpga/src/fabric/build_device_module.cpp index f255b773f..90778f8b7 100644 --- a/openfpga/src/fabric/build_device_module.cpp +++ b/openfpga/src/fabric/build_device_module.cpp @@ -20,6 +20,7 @@ #include "build_top_module.h" #include "build_wire_modules.h" #include "command_exit_codes.h" +#include "openfpga_naming.h" /* begin namespace openfpga */ namespace openfpga { @@ -127,11 +128,15 @@ int build_device_module_graph( } /******************************************************************** - * The main function to be called for adding the fpga_core wrapper to a FPGA fabric + * The main function to be called for adding the fpga_core wrapper to a FPGA + *fabric * - Rename existing fpga_top to fpga_core * - Create a wrapper module 'fpga_top' on the fpga_core *******************************************************************/ -int add_fpga_core_to_device_module_graph(ModuleManager& module_manager, const bool& verbose) { +int add_fpga_core_to_device_module_graph(ModuleManager& module_manager, + const std::string& core_inst_name, + const bool& frame_view, + const bool& verbose) { int status = CMD_EXEC_SUCCESS; /* Execute the module graph api */ @@ -140,15 +145,24 @@ int add_fpga_core_to_device_module_graph(ModuleManager& module_manager, const bo if (!module_manager.valid_module_id(top_module)) { return CMD_EXEC_FATAL_ERROR; } - /* TODO: Use a constant for the top_module name */ /* Rename existing top module to fpga_core */ - module_manager.set_module_name(top_module, "fpga_core"); + std::string core_module_name = generate_fpga_core_module_name(); + module_manager.set_module_name(top_module, core_module_name); + VTR_LOGV(verbose, "Rename current top-level module '%s' to '%s'\n", + top_module_name.c_str(), core_module_name.c_str()); + /* Create a wrapper module under the existing fpga_top */ - ModuleId new_top_module = module_manager.create_wrapper(top_module, top_module_name), + ModuleId new_top_module = module_manager.create_wrapper_module( + top_module, top_module_name, core_inst_name, frame_view); if (!module_manager.valid_module_id(new_top_module)) { + VTR_LOGV_ERROR(verbose, + "Failed to create a wrapper module '%s' on top of '%s'!\n", + top_module_name.c_str(), core_module_name.c_str()); return CMD_EXEC_FATAL_ERROR; } + VTR_LOGV(verbose, "Created a wrapper module '%s' on top of '%s'\n", + top_module_name.c_str(), core_module_name.c_str()); return status; } diff --git a/openfpga/src/fabric/build_device_module.h b/openfpga/src/fabric/build_device_module.h index e11ae0bf9..9ab88547b 100644 --- a/openfpga/src/fabric/build_device_module.h +++ b/openfpga/src/fabric/build_device_module.h @@ -23,7 +23,10 @@ int build_device_module_graph( const bool& duplicate_grid_pin, const FabricKey& fabric_key, const bool& generate_random_fabric_key, const bool& verbose); -int add_fpga_core_to_device_module_graph(ModuleManager& module_manager, const bool& verbose); +int add_fpga_core_to_device_module_graph(ModuleManager& module_manager, + const std::string& core_inst_name, + const bool& frame_view, + const bool& verbose); } /* end namespace openfpga */ diff --git a/openfpga/src/fabric/module_manager.cpp b/openfpga/src/fabric/module_manager.cpp index b1474835a..fb584cd38 100644 --- a/openfpga/src/fabric/module_manager.cpp +++ b/openfpga/src/fabric/module_manager.cpp @@ -768,6 +768,14 @@ void ModuleManager::set_port_is_wire(const ModuleId& module, port_is_wire_[module][port] = is_wire; } +/* Set a port to be a wire */ +void ModuleManager::set_port_is_wire(const ModuleId& module, + const ModulePortId& port_id, + const bool& is_wire) { + VTR_ASSERT(valid_module_port_id(module, port_id)); + port_is_wire_[module][port_id] = is_wire; +} + /* Set a port to be a mappable I/O */ void ModuleManager::set_port_is_mappable_io(const ModuleId& module, const ModulePortId& port_id, @@ -788,6 +796,14 @@ void ModuleManager::set_port_is_register(const ModuleId& module, port_is_register_[module][port] = is_register; } +/* Set a port to be a register */ +void ModuleManager::set_port_is_register(const ModuleId& module, + const ModulePortId& port_id, + const bool& is_register) { + VTR_ASSERT(valid_module_port_id(module, port_id)); + port_is_register_[module][port_id] = is_register; +} + /* Set the preprocessing flag for a port */ void ModuleManager::set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, @@ -1185,6 +1201,93 @@ ModuleNetSinkId ModuleManager::add_module_net_sink( return net_sink; } +ModuleId ModuleManager::create_wrapper_module( + const ModuleId& existing_module, const std::string& wrapper_module_name, + const std::string& instance_name, const bool& add_nets) { + /* Create a new module with the given name */ + ModuleId wrapper_module = add_module(wrapper_module_name); + if (!wrapper_module) { + return wrapper_module; + } + /* Add the existing module as an instance */ + add_child_module(wrapper_module, existing_module, false); + set_child_instance_name(wrapper_module, existing_module, 0, instance_name); + + /* A fast-lookup on the port linking: wrapper_module port -> existing_module + * port */ + std::map port_map; + /* Herit ports */ + for (ModulePortId existing_port : module_ports(existing_module)) { + /* Create new port */ + BasicPort existing_port_info = module_port(existing_module, existing_port); + ModuleManager::e_module_port_type existing_port_type = + port_type(existing_module, existing_port); + ModulePortId new_port = + add_port(wrapper_module, existing_port_info, existing_port_type); + /* Set port attributes */ + set_port_is_wire(wrapper_module, new_port, + port_is_wire(existing_module, existing_port)); + set_port_is_mappable_io( + wrapper_module, new_port, + port_is_mappable_io(existing_module, existing_port)); + set_port_is_register(wrapper_module, new_port, + port_is_register(existing_module, existing_port)); + set_port_preproc_flag(wrapper_module, new_port, + port_preproc_flag(existing_module, existing_port)); + /* Register in port mapping */ + port_map[new_port] = existing_port; + } + + /* Add nets */ + if (!add_nets) { + return wrapper_module; + } + /* The number of nets are the sum of input and output pins */ + size_t num_nets_to_reserve = 0; + for (ModulePortId new_port : module_ports(wrapper_module)) { + BasicPort new_port_info = module_port(wrapper_module, new_port); + num_nets_to_reserve += new_port_info.get_width(); + } + reserve_module_nets(wrapper_module, num_nets_to_reserve); + for (ModulePortId new_port : module_ports(wrapper_module)) { + BasicPort new_port_info = module_port(wrapper_module, new_port); + /* Create new net */ + ModuleNetId new_net = create_module_net(wrapper_module); + VTR_ASSERT(valid_module_net_id(wrapper_module, new_net)); + /* For each input pin, create a new source */ + ModuleManager::e_module_port_type new_port_type = + port_type(wrapper_module, new_port); + /* Check if the pin size are matching or not */ + ModulePortId existing_port = port_map[new_port]; + BasicPort existing_port_info = module_port(existing_module, existing_port); + VTR_ASSERT(existing_port_info == new_port_info); + reserve_module_net_sources(wrapper_module, new_net, + new_port_info.pins().size()); + reserve_module_net_sinks(wrapper_module, new_net, + new_port_info.pins().size()); + if (new_port_type != + ModuleManager::e_module_port_type::MODULE_OUTPUT_PORT) { + for (auto pin : new_port_info.pins()) { + add_module_net_source(wrapper_module, new_net, wrapper_module, 0, + new_port, pin); + add_module_net_sink(wrapper_module, new_net, existing_module, 0, + existing_port, pin); + } + } else { + VTR_ASSERT_SAFE(new_port_type == + ModuleManager::e_module_port_type::MODULE_OUTPUT_PORT); + for (auto pin : new_port_info.pins()) { + add_module_net_source(wrapper_module, new_net, existing_module, 0, + existing_port, pin); + add_module_net_sink(wrapper_module, new_net, wrapper_module, 0, + new_port, pin); + } + } + } + + return wrapper_module; +} + /****************************************************************************** * Public Deconstructor ******************************************************************************/ diff --git a/openfpga/src/fabric/module_manager.h b/openfpga/src/fabric/module_manager.h index 2c8633b42..dd0f299dc 100644 --- a/openfpga/src/fabric/module_manager.h +++ b/openfpga/src/fabric/module_manager.h @@ -317,6 +317,8 @@ class ModuleManager { /* Set a port to be a wire */ void set_port_is_wire(const ModuleId& module, const std::string& port_name, const bool& is_wire); + void set_port_is_wire(const ModuleId& module, const ModulePortId& port_id, + const bool& is_wire); /* Set a port to be mappable to an I/O from users' implemenations */ void set_port_is_mappable_io(const ModuleId& module, const ModulePortId& port_id, @@ -325,6 +327,8 @@ class ModuleManager { void set_port_is_register(const ModuleId& module, const std::string& port_name, const bool& is_register); + void set_port_is_register(const ModuleId& module, const ModulePortId& port_id, + const bool& is_register); /* Set the preprocessing flag for a port */ void set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag); @@ -423,6 +427,26 @@ class ModuleManager { const ModulePortId& sink_port, const size_t& sink_pin); + /** @brief Create a wrapper module on an existing module. The wrapper module + * will herit all the ports with the same direction, width and names from the + * selected module. The wrapper module will contain the existing module. For + * example, + * + * Wrapper module + * +------------------------+ + * | existing module | + * | +------------------+ | + * | | | | + * a ->+->+ a b-+--+-> b + * | | | | + * | +------------------+ | + * +------------------------+ + */ + ModuleId create_wrapper_module(const ModuleId& existing_module, + const std::string& wrapper_module_name, + const std::string& instance_name, + const bool& add_nets); + public: /* Public deconstructors */ /* This is a strong function which will remove all the configurable children * under a given parent module