[core] io name map now supports dummy port direction

This commit is contained in:
tangxifan 2023-06-23 11:09:33 -07:00
parent 0811409c4f
commit 8bd9ae02fd
8 changed files with 116 additions and 57 deletions

View File

@ -119,7 +119,8 @@ 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 {
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)) {
@ -131,7 +132,9 @@ IoNameMap::e_dummy_port_direction IoNameMap::fpga_top_dummy_port_direction(const
}
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();
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,
@ -203,7 +206,8 @@ int IoNameMap::set_io_pair(const BasicPort& fpga_top_port,
return CMD_EXEC_SUCCESS;
}
int IoNameMap::set_dummy_io(const BasicPort& fpga_top_port, const e_dummy_port_direction& direction) {
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 */
@ -236,7 +240,8 @@ int IoNameMap::set_dummy_io(const BasicPort& fpga_top_port, const e_dummy_port_d
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",
"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;
}
@ -246,7 +251,7 @@ int IoNameMap::set_dummy_io(const BasicPort& fpga_top_port, const e_dummy_port_d
}
if (!dir_defined) {
dummy_port_direction_[top_port_str] = direction;
}
}
return CMD_EXEC_SUCCESS;
}
@ -258,20 +263,43 @@ BasicPort IoNameMap::str2port(const std::string& port_str) const {
return PortParser(port_str).port();
}
IoNameMap::e_dummy_port_direction IoNameMap::str2dummy_port_dir(const std::string& dir_str, const bool& verbose) const {
for (int itype = IoNameMap::e_dummy_port_direction::INPUT; itype != IoNameMap::e_dummy_direction::NUM_TYPES; ++itype) {
if (dir_str == std::string(DUMMY_PORT_DIR_STRING_[itype])) {
return static_case<IoNameMap::e_dummy_port_direction>(itype);
}
}
std::string IoNameMap::dummy_port_dir_all2str() const {
std::string full_types = "[";
for (int itype = IoNameMap::e_dummy_port_direction::INPUT; itype != IoNameMap::e_dummy_direction::NUM_TYPES; ++itype) {
for (int itype = size_t(IoNameMap::e_dummy_port_direction::INPUT);
itype != size_t(IoNameMap::e_dummy_port_direction::NUM_TYPES); ++itype) {
full_types += std::string(DUMMY_PORT_DIR_STRING_[itype]) + std::string("|");
}
}
full_types.pop_back();
full_types += "]";
VTR_LOGV_ERROR(verbose, "Invalid direction for dummy port! Expect %s\n", full_types.c_str());
return full_types;
}
IoNameMap::e_dummy_port_direction IoNameMap::str2dummy_port_dir(
const std::string& dir_str, const bool& verbose) const {
for (int itype = size_t(IoNameMap::e_dummy_port_direction::INPUT);
itype != size_t(IoNameMap::e_dummy_port_direction::NUM_TYPES); ++itype) {
if (dir_str == std::string(DUMMY_PORT_DIR_STRING_[itype])) {
return static_cast<IoNameMap::e_dummy_port_direction>(itype);
}
}
VTR_LOGV_ERROR(verbose, "Invalid direction for dummy port! Expect %s\n",
dummy_port_dir_all2str().c_str());
return IoNameMap::e_dummy_port_direction::NUM_TYPES;
}
std::string IoNameMap::dummy_port_dir2str(const e_dummy_port_direction& dir,
const bool& verbose) const {
if (!valid_dummy_port_direction(dir)) {
VTR_LOGV_ERROR(verbose, "Invalid direction for dummy port! Expect %s\n",
dummy_port_dir_all2str().c_str());
return std::string();
}
return std::string(DUMMY_PORT_DIR_STRING_[size_t(dir)]);
}
bool IoNameMap::valid_dummy_port_direction(
const IoNameMap::e_dummy_port_direction& direction) const {
return direction != IoNameMap::e_dummy_port_direction::NUM_TYPES;
}
} /* end namespace openfpga */

View File

@ -20,12 +20,8 @@ namespace openfpga {
*/
class IoNameMap {
public: /* Types */
enum class e_dummy_port_direction {
INPUT = 0,
OUTPUT,
INOUT,
NUM_TYPES
};
enum class e_dummy_port_direction { INPUT = 0, OUTPUT, INOUT, NUM_TYPES };
public: /* Public accessors */
/** @brief Get all the fpga top ports */
std::vector<BasicPort> fpga_top_ports() const;
@ -38,7 +34,8 @@ class IoNameMap {
/** @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;
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;
@ -49,17 +46,29 @@ 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, const e_dummy_port_direction& direction);
int set_dummy_io(const BasicPort& fpga_top_port,
const e_dummy_port_direction& direction);
public: /* Public utility */
/** @brief Parse the dummy port direction from string to valid type. Parser error can be turned on */
e_dummy_port_direction str2dummy_port_dir(const std::string& dir_str, const bool& verbose = false) const;
/** @brief Parse the dummy port direction from string to valid type. Parser
* error can be turned on */
e_dummy_port_direction str2dummy_port_dir(const std::string& dir_str,
const bool& verbose = false) const;
/** @brief Output the string representing dummy port direction */
std::string dummy_port_dir2str(const e_dummy_port_direction& dir,
const bool& verbose = false) const;
/** @brief Validate the dummy port direction */
bool valid_dummy_port_direction(
const e_dummy_port_direction& direction) const;
private: /* Internal utility */
/* Convert a port info to string, which can be used to store keys */
std::string port2str(const BasicPort& port) const;
/* Convert a string to port, which can be used to echo internal info */
BasicPort str2port(const std::string& port_str) const;
/* Generate a string include all the valid directions of the dummy port.
* Useful for printing debugging messages */
std::string dummy_port_dir_all2str() const;
private: /* Internal Data */
/* fpga_top -> fpga_core io_name_keys. Use the port name to find all the port
@ -76,7 +85,8 @@ class IoNameMap {
std::map<std::string, e_dummy_port_direction> dummy_port_direction_;
/* Constants */
std::array<const char*, e_dummy_port_direction::NUM_TYPES> DUMMY_PORT_DIR_STRING_;
std::array<const char*, size_t(e_dummy_port_direction::NUM_TYPES)>
DUMMY_PORT_DIR_STRING_;
};
} /* End namespace openfpga*/

View File

@ -10,6 +10,8 @@ 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
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

@ -11,6 +11,7 @@
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* Headers from libopenfpga util library */
@ -45,12 +46,15 @@ static int read_xml_io_map_port(pugi::xml_node& xml_port,
std::string dir_str =
get_attribute(xml_port, XML_IO_NAME_MAP_ATTRIBUTE_DIRECTION, loc_data)
.as_string();
IoNameMap::e_dummy_port_direction dummy_port_dir = io_name_map.str2dummy_port_dir(dir_str, true);
IoNameMap::e_dummy_port_direction dummy_port_dir =
io_name_map.str2dummy_port_dir(dir_str, true);
if (!io_name_map.valid_dummy_port_direction(dummy_port_dir)) {
VTR_LOG_ERROR("Invalid direction for dummy port '%s'!\n", top_port.to_verilog_string().c_str());
VTR_LOG_ERROR("Invalid direction for dummy port '%s'!\n",
top_port.to_verilog_string().c_str());
return CMD_EXEC_FATAL_ERROR;
}
return io_name_map.set_dummy_io(top_port, dummy_port_dir); /* Early return */
return io_name_map.set_dummy_io(top_port,
dummy_port_dir); /* Early return */
}
/* This is not a dummy io, create the io mapping */

View File

@ -44,6 +44,10 @@ static int write_xml_io_map_port(std::fstream& fp, const IoNameMap& io_name_map,
if (io_name_map.fpga_top_port_is_dummy(fpga_top_port)) {
write_xml_attribute(fp, XML_IO_NAME_MAP_ATTRIBUTE_IS_DUMMY, "true");
IoNameMap::e_dummy_port_direction dir =
io_name_map.fpga_top_dummy_port_direction(fpga_top_port);
write_xml_attribute(fp, XML_IO_NAME_MAP_ATTRIBUTE_DIRECTION,
io_name_map.dummy_port_dir2str(dir, true).c_str());
} else {
BasicPort fpga_core_port = io_name_map.fpga_core_port(fpga_top_port);
write_xml_attribute(fp, XML_IO_NAME_MAP_ATTRIBUTE_CORE_NAME,

View File

@ -6,6 +6,7 @@
#include "build_device_module.h"
#include "build_fabric_global_port_info.h"
#include "build_fabric_io_location_map.h"
#include "build_fpga_core_wrapper_module.h"
#include "command.h"
#include "command_context.h"
#include "command_exit_codes.h"
@ -254,12 +255,13 @@ int add_fpga_core_to_fabric_template(T& openfpga_ctx, const Command& cmd,
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);
read_xml_io_name_map(cmd_context.option_value(cmd, opt_io_naming).c_str(),
io_name_map);
}
return add_fpga_core_to_device_module_graph(
openfpga_ctx.mutable_module_graph(), io_name_map, core_inst_name, frame_view,
verbose_output);
openfpga_ctx.mutable_module_graph(), io_name_map, core_inst_name,
frame_view, verbose_output);
}
} /* end namespace openfpga */

View File

@ -9,9 +9,9 @@
#include "vtr_time.h"
/* Headers from openfpgashell library */
#include "build_fpga_core_wrapper_module.h"
#include "command_exit_codes.h"
#include "openfpga_naming.h"
#include "build_fpga_core_wrapper_module.h"
/* begin namespace openfpga */
namespace openfpga {
@ -19,14 +19,10 @@ 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) {
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) {
@ -34,41 +30,50 @@ int create_fpga_top_module_using_naming_rules(ModuleManager& module_manager,
}
/* 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);
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 */
/* 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)) {
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)) {
} 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));
} 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());
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);
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());
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, );
// module_manager.add_port(wrapper_module, top_port, );
}
/* TODO: Add nets */
if (add_nets) {
}
/* TODO: Update the fabric global ports */
@ -103,7 +108,8 @@ int add_fpga_core_to_device_module_graph(ModuleManager& module_manager,
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 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;
@ -117,7 +123,9 @@ int add_fpga_core_to_device_module_graph(ModuleManager& module_manager,
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);
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;
}

View File

@ -4,10 +4,11 @@
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "module_manager.h"
#include "io_name_map.h"
#include <string>
#include "io_name_map.h"
#include "module_manager.h"
/********************************************************************
* Function declaration
*******************************************************************/