[core] enabling io naming rules in fabric builder
This commit is contained in:
parent
4d265c3965
commit
7961223eac
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ target_link_libraries(libopenfpga
|
|||
libpcf
|
||||
libvtrutil
|
||||
libbusgroup
|
||||
libionamemap
|
||||
libpugixml
|
||||
libvpr)
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
Loading…
Reference in New Issue