[core] enabling io naming rules in fabric builder

This commit is contained in:
tangxifan 2023-06-22 22:18:09 -07:00
parent 4d265c3965
commit 7961223eac
10 changed files with 235 additions and 56 deletions

View File

@ -119,6 +119,21 @@ bool IoNameMap::fpga_top_port_is_dummy(const BasicPort& fpga_top_port) const {
return !fpga_core_port(fpga_top_port).is_valid();
}
IoNameMap::e_dummy_port_direction IoNameMap::fpga_top_dummy_port_direction(const BasicPort& fpga_top_port) const {
for (auto& kv : dummy_port_direction_) {
BasicPort cand = str2port(kv.first);
if (cand.contained(fpga_top_port)) {
return kv.second;
}
}
/* Return an invalid port type */
return IoNameMap::e_dummy_port_direction::NUM_TYPES;
}
bool IoNameMap::empty() const {
return top2core_io_name_keys_.empty() && top2core_io_name_map_.empty() && core2top_io_name_keys_.empty() && core2top_io_name_map_.empty() && dummy_port_direction_.empty();
}
int IoNameMap::set_io_pair(const BasicPort& fpga_top_port,
const BasicPort& fpga_core_port) {
/* Ensure the two ports are matching in size */
@ -152,7 +167,7 @@ int IoNameMap::set_io_pair(const BasicPort& fpga_top_port,
VTR_LOG_WARN(
"Overwrite the top-to-core pin mapping: top pin '%s' to core pin "
"'%s' (previously was '%s')!\n",
top_port_str, port2str(fpga_core_port).c_str(),
top_port_str.c_str(), port2str(fpga_core_port).c_str(),
port2str(top2core_io_name_map_[top_port_str]).c_str());
top2core_io_name_map_[top_port_str] = fpga_core_port;
}
@ -179,7 +194,7 @@ int IoNameMap::set_io_pair(const BasicPort& fpga_top_port,
VTR_LOG_WARN(
"Overwrite the core-to-top pin mapping: core pin '%s' to top pin "
"'%s' (previously was '%s')!\n",
core_port_str, port2str(fpga_top_port).c_str(),
core_port_str.c_str(), port2str(fpga_top_port).c_str(),
port2str(core2top_io_name_map_[core_port_str]).c_str());
core2top_io_name_map_[core_port_str] = fpga_top_port;
}
@ -188,7 +203,7 @@ int IoNameMap::set_io_pair(const BasicPort& fpga_top_port,
return CMD_EXEC_SUCCESS;
}
int IoNameMap::set_dummy_io(const BasicPort& fpga_top_port) {
int IoNameMap::set_dummy_io(const BasicPort& fpga_top_port, const e_dummy_port_direction& direction) {
/* Must be a true dummy port, none of its pins have been paired! */
std::string top_port_str = port2str(fpga_top_port);
/* First, find the pin name matching */
@ -210,8 +225,28 @@ int IoNameMap::set_dummy_io(const BasicPort& fpga_top_port) {
"to a valid pin '%s' of fpga_core!\n",
port2str(fpga_top_port).c_str(),
port2str(top2core_io_name_map_[top_port_str]).c_str());
return CMD_EXEC_FATAL_ERROR;
}
}
/* Add the direction list */
bool dir_defined = false;
for (auto& kv : dummy_port_direction_) {
BasicPort cand = str2port(kv.first);
if (cand.contained(fpga_top_port)) {
if (kv.second != direction) {
/* Throw a error because the dummy pin should NOT be mapped before! */
VTR_LOG_ERROR(
"Dummy port '%s' of fpga_top is already assigned to a different direction through another dummy port definition '%s'!\n",
port2str(fpga_top_port).c_str(), port2str(cand).c_str());
return CMD_EXEC_FATAL_ERROR;
}
dir_defined = true;
break;
}
}
if (!dir_defined) {
dummy_port_direction_[top_port_str] = direction;
}
return CMD_EXEC_SUCCESS;
}

View File

@ -19,6 +19,13 @@ namespace openfpga {
* - the corresponding port of fpga_top, with a given port of fpga_core
*/
class IoNameMap {
public: /* Types */
enum class e_dummy_port_direction {
INPUT,
OUTPUT,
INOUT,
NUM_TYPES
};
public: /* Public accessors */
/** @brief Get all the fpga top ports */
std::vector<BasicPort> fpga_top_ports() const;
@ -30,6 +37,10 @@ class IoNameMap {
BasicPort fpga_top_port(const BasicPort& fpga_core_port) const;
/** @brief Identify if the fpga_top port is dummy or not */
bool fpga_top_port_is_dummy(const BasicPort& fpga_top_port) const;
/** @brief Get the direction of a dummy port */
e_dummy_port_direction fpga_top_dummy_port_direction(const BasicPort& fpga_top_port) const;
/** @brief Identify if there are any naming rules inside */
bool empty() const;
public: /* Public mutators */
/** @brief Create the one-on-one mapping between an port of fpga_top and
@ -38,7 +49,7 @@ class IoNameMap {
const BasicPort& fpga_core_port);
/** @brief Add a dummy port at the fpga top, which is not mapped any port at
* fpga_core */
int set_dummy_io(const BasicPort& fpga_top_port);
int set_dummy_io(const BasicPort& fpga_top_port, const e_dummy_port_direction& direction);
private: /* Internal utility */
/* Convert a port info to string, which can be used to store keys */
@ -57,6 +68,8 @@ class IoNameMap {
std::map<std::string, std::vector<std::string>> core2top_io_name_keys_;
std::map<std::string, BasicPort> core2top_io_name_map_;
std::map<std::string, e_dummy_port_direction> dummy_port_direction_;
};
} /* End namespace openfpga*/

View File

@ -8,5 +8,8 @@ constexpr const char* XML_IO_NAME_MAP_NODE_NAME = "port";
constexpr const char* XML_IO_NAME_MAP_ATTRIBUTE_TOP_NAME = "top_name";
constexpr const char* XML_IO_NAME_MAP_ATTRIBUTE_CORE_NAME = "core_name";
constexpr const char* XML_IO_NAME_MAP_ATTRIBUTE_IS_DUMMY = "is_dummy";
constexpr const char* XML_IO_NAME_MAP_ATTRIBUTE_DIRECTION = "direction";
constexpr std::array<const char*, 3> XML_IO_NAME_MAP_DUMMY_PORT_DIRECTION_STRING = {{"input", "output", "inout"}}; //String versions of side orientations
#endif

View File

@ -42,6 +42,14 @@ static int read_xml_io_map_port(pugi::xml_node& xml_port,
loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_bool(false);
if (is_dummy) {
std::string dir_str =
get_attribute(xml_port, XML_IO_NAME_MAP_ATTRIBUTE_DIRECTION, loc_data)
.as_string();
for (auto acceptable_dir_str : XML_IO_NAME_MAP_DUMMY_PORT_DIRECTION_STRING) {
if (dir_str == std::string(acceptable_dir_str)) {
}
}
return io_name_map.set_dummy_io(top_port); /* Early return */
}

View File

@ -41,6 +41,7 @@ target_link_libraries(libopenfpga
libpcf
libvtrutil
libbusgroup
libionamemap
libpugixml
libvpr)

View File

@ -16,6 +16,7 @@
#include "globals.h"
#include "openfpga_naming.h"
#include "read_xml_fabric_key.h"
#include "read_xml_io_name_map.h"
#include "vtr_log.h"
#include "vtr_time.h"
@ -249,8 +250,15 @@ int add_fpga_core_to_fabric_template(T& openfpga_ctx, const Command& cmd,
core_inst_name = cmd_context.option_value(cmd, opt_inst_name);
}
/* Handle I/O naming rules if defined */
IoNameMap io_name_map;
CommandOptionId opt_io_naming = cmd.option("io_naming");
if (true == cmd_context.option_enable(cmd, opt_io_naming)) {
read_xml_io_name_map(cmd_context.option_value(cmd, opt_io_naming), io_name_map);
}
return add_fpga_core_to_device_module_graph(
openfpga_ctx.mutable_module_graph(), core_inst_name, frame_view,
openfpga_ctx.mutable_module_graph(), io_name_map, core_inst_name, frame_view,
verbose_output);
}

View File

@ -127,50 +127,4 @@ int build_device_module_graph(
return status;
}
/********************************************************************
* 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 std::string& core_inst_name,
const bool& frame_view,
const bool& verbose) {
int status = CMD_EXEC_SUCCESS;
/* Execute the module graph api */
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
if (!module_manager.valid_module_id(top_module)) {
return CMD_EXEC_FATAL_ERROR;
}
/* Rename existing top module to 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_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());
/* Now fpga_core should be the only configurable child under the top-level
* module */
module_manager.add_configurable_child(new_top_module, top_module, 0);
/* TODO: Update the fabric global ports */
return status;
}
} /* end namespace openfpga */

View File

@ -5,6 +5,7 @@
* Include header files that are required by function declaration
*******************************************************************/
#include "fabric_key.h"
#include "io_name_map.h"
#include "openfpga_context.h"
#include "vpr_context.h"
@ -23,11 +24,6 @@ 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 std::string& core_inst_name,
const bool& frame_view,
const bool& verbose);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,135 @@
/********************************************************************
* This file includes the main function to build module graphs
* for the FPGA fabric
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* Headers from openfpgashell library */
#include "command_exit_codes.h"
#include "openfpga_naming.h"
#include "build_fpga_core_wrapper_module.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Create a custom fpga_top module by applying naming rules
*******************************************************************/
static
int create_fpga_top_module_using_naming_rules(ModuleManager& module_manager,
const ModuleId& core_module,
const std::string& top_module_name,
const IoNameMap& io_naming,
const std::string& instance_name,
const bool& add_nets,
const bool& verbose) {
/* Create a new module with the given name */
ModuleId wrapper_module = module_manager.add_module(top_module_name);
if (!wrapper_module) {
return CMD_EXEC_FATAL_ERROR;
}
/* Add the existing module as an instance */
module_manager.add_child_module(wrapper_module, core_module, false);
module_manager.set_child_instance_name(wrapper_module, core_module, 0, instance_name);
/* TODO: Add ports from I/O naming rules:
* - Add ports which has been defined in the naming rules
* - Add ports from the core module, which does not appear in the naming rules
*/
for (BasicPort top_port : io_naming.fpga_top_ports()) {
/* For dummy port, just add it. Port type should be defined from io naming rules */
if (io_naming.fpga_top_port_is_dummy(top_port)) {
ModuleManager::e_module_port_type port_type = ModuleManager::e_module_port_type::MODULE_INOUT_PORT;
if (IoNameMap::e_dummy_port_direction::INPUT == io_naming.fpga_top_dummy_port_direction(top_port)) {
port_type = ModuleManager::e_module_port_type::MODULE_INPUT_PORT;
} else if (IoNameMap::e_dummy_port_direction::OUTPUT == io_naming.fpga_top_dummy_port_direction(top_port)) {
port_type = ModuleManager::e_module_port_type::MODULE_OUTPUT_PORT;
} else if (IoNameMap::e_dummy_port_direction::INOUT == io_naming.fpga_top_dummy_port_direction(top_port));
port_type = ModuleManager::e_module_port_type::MODULE_INOUT_PORT;
} else {
VTR_LOG_ERROR("fpga_top dummy port '%s' has an invalid direction. Expect [input|output|inout]!\n", top_port.to_verilog_string().c_str());
return CMD_EXEC_FATAL_ERROR;
}
module_manager.add_port(wrapper_module, top_port, port_type);
continue; /* Finish for this port addition */
}
/* Get the port type which should be same as the fpga_core port */
BasicPort core_port : io_naming.fpga_core_port(top_port);
if (!core_port.is_valid()) {
VTR_LOG_ERROR("fpga_top port '%s' is not mapped to any fpga_core port!\n", core_port.to_verilog_string().c_str());
return CMD_EXEC_FATAL_ERROR;
}
//module_manager.add_port(wrapper_module, top_port, );
}
/* TODO: Add nets */
if (add_nets) {
}
/* TODO: Update the fabric global ports */
return CMD_EXEC_SUCCESS;
}
/********************************************************************
* 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 IoNameMap& io_naming,
const std::string& core_inst_name,
const bool& frame_view,
const bool& verbose) {
int status = CMD_EXEC_SUCCESS;
/* Execute the module graph api */
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
if (!module_manager.valid_module_id(top_module)) {
return CMD_EXEC_FATAL_ERROR;
}
/* Rename existing top module to 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
* - if there are no io naming rules, just use the default API to create a wrapper
* - if there are io naming rules, use dedicated function to handle
*/
ModuleId new_top_module;
if (io_naming.empty()) {
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;
}
} else {
status = create_fpga_top_module_using_naming_rules(module_manager, top_module, top_module_name, io_naming, core_inst_name, !frame_view, verbose);
if (CMD_EXEC_SUCCESS != status) {
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());
/* Now fpga_core should be the only configurable child under the top-level
* module */
module_manager.add_configurable_child(new_top_module, top_module, 0);
return status;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,26 @@
#ifndef BUILD_FPGA_CORE_WRAPPER_MODULE_H
#define BUILD_FPGA_CORE_WRAPPER_MODULE_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "module_manager.h"
#include "io_name_map.h"
#include <string>
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
int add_fpga_core_to_device_module_graph(ModuleManager& module_manager,
const IoNameMap& io_naming,
const std::string& core_inst_name,
const bool& frame_view,
const bool& verbose);
} /* end namespace openfpga */
#endif