[engine] now support a custom list for indexing I/O children in each module

This commit is contained in:
tangxifan 2022-09-14 15:54:55 -07:00
parent ec38b3990f
commit cb89488f76
6 changed files with 234 additions and 200 deletions

View File

@ -28,6 +28,8 @@ namespace openfpga {
/********************************************************************
* Find all the GPIO ports in the grid module
* and cache their port/pin index in the top-level module
*
* .. note:: The I/O sequence(indexing) is already determined in the io_children() list of top-level module. Here we just build a fast lookup from (x, y, z) coordinate to the actual indices
*******************************************************************/
IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager,
const DeviceGrid& grids) {
@ -37,132 +39,61 @@ IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager,
std::map<std::string, size_t> io_counter;
/* Create the coordinate range for each side of FPGA fabric */
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates = generate_perimeter_grid_coordinates( grids);
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
/* Walk through all the grids on the perimeter, which are I/O grids */
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
for (const vtr::Point<size_t>& io_coordinate : io_coordinates[io_side]) {
/* Bypass EMPTY grid */
if (true == is_empty_type(grids[io_coordinate.x()][io_coordinate.y()].type)) {
continue;
}
/* Walk through the I/O child list */
for (size_t ichild = 0; ichild < module_manager.io_children(top_module).size(); ++ichild) {
ModuleId child = module_manager.io_children(top_module)[ichild];
vtr::Point<int> coord = module_manager.io_child_coordinates(top_module)[ichild];
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ( (0 < grids[io_coordinate.x()][io_coordinate.y()].width_offset)
|| (0 < grids[io_coordinate.x()][io_coordinate.y()].height_offset)) {
continue;
}
/* Bypass EMPTY grid */
if (true == is_empty_type(grids[coord.x()][coord.y()].type)) {
continue;
}
t_physical_tile_type_ptr grid_type = grids[io_coordinate.x()][io_coordinate.y()].type;
/* Find the module name for this type of grid */
std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX);
std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), is_io_type(grid_type), io_side);
ModuleId grid_module = module_manager.find_module(grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
/* Find all the GPIO ports in the grid module */
/* MUST DO: register in io location mapping!
* I/O location mapping is a critical look-up for testbench generators
* As we add the I/O grid instances to top module by following order:
* TOP -> RIGHT -> BOTTOM -> LEFT
* The I/O index will increase in this way as well.
* This organization I/O indices is also consistent to the way
* that GPIOs are wired in function connect_gpio_module()
*
* Note: if you change the GPIO function, you should update here as well!
*/
for (int z = 0; z < grids[io_coordinate.x()][io_coordinate.y()].type->capacity; ++z) {
for (const ModuleManager::e_module_port_type& module_io_port_type : MODULE_IO_PORT_TYPES) {
for (const ModulePortId& gpio_port_id : module_manager.module_port_ids_by_type(grid_module, module_io_port_type)) {
/* Only care mappable I/O */
if (false == module_manager.port_is_mappable_io(grid_module, gpio_port_id)) {
continue;
}
const BasicPort& gpio_port = module_manager.module_port(grid_module, gpio_port_id);
auto curr_io_index = io_counter.find(gpio_port.get_name());
/* Index always start from zero */
if (curr_io_index == io_counter.end()) {
io_counter[gpio_port.get_name()] = 0;
}
io_location_map.set_io_index(io_coordinate.x(), io_coordinate.y(), z,
gpio_port.get_name(),
io_counter[gpio_port.get_name()]);
io_counter[gpio_port.get_name()]++;
}
}
}
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ( (0 < grids[coord.x()][coord.y()].width_offset)
|| (0 < grids[coord.x()][coord.y()].height_offset)) {
continue;
}
}
/* Walk through all the center grids, which may include I/O grids */
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
/* Bypass EMPTY grid */
if (true == is_empty_type(grids[ix][iy].type)) {
continue;
}
VTR_ASSERT_SAFE(true == module_manager.valid_module_id(child));
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ( (0 < grids[ix][iy].width_offset)
|| (0 < grids[ix][iy].height_offset)) {
continue;
}
/* Find all the GPIO ports in the grid module */
t_physical_tile_type_ptr grid_type = grids[ix][iy].type;
/* MUST DO: register in io location mapping!
* I/O location mapping is a critical look-up for testbench generators
*/
VTR_ASSERT(size_t(grids[coord.x()][coord.y()].type->capacity) == module_manager.io_children(child).size());
for (size_t isubchild = 0; isubchild < module_manager.io_children(child).size(); ++isubchild) {
vtr::Point<int> subchild_coord = module_manager.io_child_coordinates(child)[isubchild];
/* Find the module name for this type of grid */
std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX);
std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), is_io_type(grid_type), NUM_SIDES);
ModuleId grid_module = module_manager.find_module(grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
/* Find all the GPIO ports in the grid module */
/* MUST DO: register in io location mapping!
* I/O location mapping is a critical look-up for testbench generators
* As we add the I/O grid instances to top module by following order:
* TOP -> RIGHT -> BOTTOM -> LEFT
* The I/O index will increase in this way as well.
* This organization I/O indices is also consistent to the way
* that GPIOs are wired in function connect_gpio_module()
*
* Note: if you change the GPIO function, you should update here as well!
*/
for (int z = 0; z < grids[ix][iy].type->capacity; ++z) {
for (const ModuleManager::e_module_port_type& module_io_port_type : MODULE_IO_PORT_TYPES) {
for (const ModulePortId& gpio_port_id : module_manager.module_port_ids_by_type(grid_module, module_io_port_type)) {
/* Only care mappable I/O */
if (false == module_manager.port_is_mappable_io(grid_module, gpio_port_id)) {
continue;
}
const BasicPort& gpio_port = module_manager.module_port(grid_module, gpio_port_id);
auto curr_io_index = io_counter.find(gpio_port.get_name());
/* Index always start from zero */
if (curr_io_index == io_counter.end()) {
io_counter[gpio_port.get_name()] = 0;
}
io_location_map.set_io_index(ix, iy, z,
gpio_port.get_name(),
io_counter[gpio_port.get_name()]);
io_counter[gpio_port.get_name()]++;
for (const ModuleManager::e_module_port_type& module_io_port_type : MODULE_IO_PORT_TYPES) {
for (const ModulePortId& gpio_port_id : module_manager.module_port_ids_by_type(child, module_io_port_type)) {
/* Only care mappable I/O */
if (false == module_manager.port_is_mappable_io(child, gpio_port_id)) {
continue;
}
const BasicPort& gpio_port = module_manager.module_port(child, gpio_port_id);
auto curr_io_index = io_counter.find(gpio_port.get_name());
/* Index always start from zero */
if (curr_io_index == io_counter.end()) {
io_counter[gpio_port.get_name()] = 0;
}
io_location_map.set_io_index(coord.x(), coord.y(), subchild_coord.x(),
gpio_port.get_name(),
io_counter[gpio_port.get_name()]);
io_counter[gpio_port.get_name()]++;
}
}
}
}
/* Check all the GPIO ports in the top-level module has been mapped */
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
for (const ModuleManager::e_module_port_type& module_io_port_type : MODULE_IO_PORT_TYPES) {
for (const ModulePortId& gpio_port_id : module_manager.module_port_ids_by_type(top_module, module_io_port_type)) {
/* Only care mappable I/O */

View File

@ -1022,7 +1022,9 @@ void build_physical_tile_module(ModuleManager& module_manager,
/* Add all the sub modules */
size_t pb_instance_id = module_manager.num_instance(grid_module, pb_module);
module_manager.add_child_module(grid_module, pb_module);
module_manager.add_child_module(grid_module, pb_module, false);
/* Add a custom I/O child with coordinate 'z' */
module_manager.add_io_child(grid_module, pb_module, pb_instance_id, vtr::Point<int>(iz, 0));
/* Give the child module with a unique instance name */
std::string instance_name = generate_physical_block_instance_name(lb_type->pb_graph_head->pb_type, iz);

View File

@ -50,7 +50,8 @@ size_t add_top_module_grid_instance(ModuleManager& module_manager,
/* Record the instance id */
size_t grid_instance = module_manager.num_instance(top_module, grid_module);
/* Add the module to top_module */
module_manager.add_child_module(top_module, grid_module);
module_manager.add_child_module(top_module, grid_module, false);
module_manager.add_io_child(top_module, grid_module, grid_instance, vtr::Point<int>(grid_coord.x(), grid_coord.y()));
/* Set an unique name to the instance
* Note: it is your risk to gurantee the name is unique!
*/
@ -205,7 +206,7 @@ vtr::Matrix<size_t> add_top_module_switch_block_instances(ModuleManager& module_
/* Record the instance id */
sb_instance_ids[rr_gsb.get_sb_x()][rr_gsb.get_sb_y()] = module_manager.num_instance(top_module, sb_module);
/* Add the module to top_module */
module_manager.add_child_module(top_module, sb_module);
module_manager.add_child_module(top_module, sb_module, false);
/* Set an unique name to the instance
* Note: it is your risk to gurantee the name is unique!
*/
@ -261,7 +262,7 @@ vtr::Matrix<size_t> add_top_module_connection_block_instances(ModuleManager& mod
/* Record the instance id */
cb_instance_ids[rr_gsb.get_cb_x(cb_type)][rr_gsb.get_cb_y(cb_type)] = module_manager.num_instance(top_module, cb_module);
/* Add the module to top_module */
module_manager.add_child_module(top_module, cb_module);
module_manager.add_child_module(top_module, cb_module, false);
/* Set an unique name to the instance
* Note: it is your risk to gurantee the name is unique!
*/
@ -354,8 +355,7 @@ int build_top_module(ModuleManager& module_manager,
}
/* Add GPIO ports from the sub-modules under this Verilog module
* This is a much easier job after adding sub modules (instances),
* we just need to find all the I/O ports from the child modules and build a list of it
* For top-level module, we follow a special sequencing for I/O modules. So we rebuild the I/O children list here
*/
add_module_gpio_ports_from_child_modules(module_manager, top_module);

View File

@ -91,6 +91,29 @@ std::vector<vtr::Point<int>> ModuleManager::configurable_child_coordinates(const
return configurable_child_coordinates_[parent_module];
}
/* Find all the configurable child modules under a parent module */
std::vector<ModuleId> ModuleManager::io_children(const ModuleId& parent_module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(parent_module));
return io_children_[parent_module];
}
/* Find all the instances of configurable child modules under a parent module */
std::vector<size_t> ModuleManager::io_child_instances(const ModuleId& parent_module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(parent_module));
return io_child_instances_[parent_module];
}
std::vector<vtr::Point<int>> ModuleManager::io_child_coordinates(const ModuleId& parent_module) const {
/* Validate the module_id */
VTR_ASSERT(valid_module_id(parent_module));
return io_child_coordinates_[parent_module];
}
/* Find the source ids of modules */
ModuleManager::module_net_src_range ModuleManager::module_net_sources(const ModuleId& module, const ModuleNetId& net) const {
/* Validate the module_id */
@ -562,6 +585,10 @@ ModuleId ModuleManager::add_module(const std::string& name) {
config_region_ids_.emplace_back();
config_region_children_.emplace_back();
io_children_.emplace_back();
io_child_instances_.emplace_back();
io_child_coordinates_.emplace_back();
port_ids_.emplace_back();
ports_.emplace_back();
port_types_.emplace_back();
@ -680,7 +707,7 @@ void ModuleManager::set_port_preproc_flag(const ModuleId& module, const ModulePo
}
/* Add a child module to a parent module */
void ModuleManager::add_child_module(const ModuleId& parent_module, const ModuleId& child_module) {
void ModuleManager::add_child_module(const ModuleId& parent_module, const ModuleId& child_module, const bool& is_io_child) {
/* Validate the id of both parent and child modules */
VTR_ASSERT ( valid_module_id(parent_module) );
VTR_ASSERT ( valid_module_id(child_module) );
@ -693,19 +720,27 @@ void ModuleManager::add_child_module(const ModuleId& parent_module, const Module
}
std::vector<ModuleId>::iterator child_it = std::find(children_[parent_module].begin(), children_[parent_module].end(), child_module);
int child_instance_id = -1;
if (child_it == children_[parent_module].end()) {
/* Update the child module of parent module */
children_[parent_module].push_back(child_module);
num_child_instances_[parent_module].push_back(1); /* By default give one */
child_instance_id = 0;
/* Update the instance name list */
child_instance_names_[parent_module].emplace_back();
child_instance_names_[parent_module].back().emplace_back();
} else {
/* Increase the counter of instances */
child_instance_id = num_child_instances_[parent_module][child_it - children_[parent_module].begin()];
num_child_instances_[parent_module][child_it - children_[parent_module].begin()]++;
child_instance_names_[parent_module][child_it - children_[parent_module].begin()].emplace_back();
}
/* Add to I/O child if needed */
if (is_io_child) {
add_io_child(parent_module, child_module, child_instance_id);
}
/* Update fast look-up for nets */
size_t instance_id = net_lookup_[parent_module][child_module].size();
net_lookup_[parent_module][child_module].emplace_back();
@ -815,6 +850,36 @@ void ModuleManager::add_configurable_child_to_region(const ModuleId& parent_modu
config_region_children_[parent_module][config_region].push_back(config_child_id);
}
void ModuleManager::add_io_child(const ModuleId& parent_module,
const ModuleId& child_module,
const size_t& child_instance,
const vtr::Point<int> coord) {
/* Validate the id of both parent and child modules */
VTR_ASSERT ( valid_module_id(parent_module) );
VTR_ASSERT ( valid_module_id(child_module) );
/* Ensure that the instance id is in range */
VTR_ASSERT ( child_instance < num_instance(parent_module, child_module));
io_children_[parent_module].push_back(child_module);
io_child_instances_[parent_module].push_back(child_instance);
io_child_coordinates_[parent_module].push_back(coord);
}
void ModuleManager::reserve_io_child(const ModuleId& parent_module,
const size_t& num_children) {
VTR_ASSERT ( valid_module_id(parent_module) );
/* Do reserve when the number of children is larger than current size of lists */
if (num_children > io_children_[parent_module].size()) {
io_children_[parent_module].reserve(num_children);
}
if (num_children > io_child_instances_[parent_module].size()) {
io_child_instances_[parent_module].reserve(num_children);
}
if (num_children > io_child_coordinates_[parent_module].size()) {
io_child_coordinates_[parent_module].reserve(num_children);
}
}
void ModuleManager::reserve_module_nets(const ModuleId& module,
const size_t& num_nets) {
/* Validate the module id */
@ -1020,6 +1085,14 @@ void ModuleManager::clear_config_region(const ModuleId& parent_module) {
config_region_children_[parent_module].clear();
}
void ModuleManager::clear_io_children(const ModuleId& parent_module) {
VTR_ASSERT(valid_module_id(parent_module));
io_children_[parent_module].clear();
io_child_instances_[parent_module].clear();
io_child_coordinates_[parent_module].clear();
}
/******************************************************************************
* Private validators/invalidators
******************************************************************************/

View File

@ -151,6 +151,14 @@ class ModuleManager {
std::vector<size_t> configurable_child_instances(const ModuleId& parent_module) const;
/* Find the coordindate of a configurable child module under a parent module */
std::vector<vtr::Point<int>> configurable_child_coordinates(const ModuleId& parent_module) const;
/* Find all the I/O child modules under a parent module */
std::vector<ModuleId> io_children(const ModuleId& parent_module) const;
/* Find all the instances of I/O child modules under a parent module */
std::vector<size_t> io_child_instances(const ModuleId& parent_module) const;
/* Find the coordindate of an I/O child module under a parent module */
std::vector<vtr::Point<int>> io_child_coordinates(const ModuleId& parent_module) const;
/* Find the source ids of modules */
module_net_src_range module_net_sources(const ModuleId& module, const ModuleNetId& net) const;
/* Find the sink ids of modules */
@ -255,8 +263,13 @@ class ModuleManager {
void set_port_is_register(const ModuleId& module, const std::string& port_name, 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);
/* Add a child module to a parent module */
void add_child_module(const ModuleId& parent_module, const ModuleId& child_module);
/** @brief Add a child module to a parent module.
* By default, it considers the child module as an I/O child, and update the children list of I/O modules inside
* It not needed, just turn it off. Then you need to call add_io_child() API to update child list
*
* .. note:: By default, we assume the I/O indexing to the same as sequence when adding child modules to a parent. However, it may not be true all the time, especially for the top-level module, where customization is needed.
*/
void add_child_module(const ModuleId& parent_module, const ModuleId& child_module, const bool& is_io_child = true);
/* Set the instance name of a child module */
void set_child_instance_name(const ModuleId& parent_module, const ModuleId& child_module, const size_t& instance_id, const std::string& instance_name);
/* Add a configurable child module to module
@ -266,9 +279,7 @@ class ModuleManager {
* By default, it is an invalid coordinate
*/
void add_configurable_child(const ModuleId& module, const ModuleId& child_module, const size_t& child_instance, const vtr::Point<int> coord = vtr::Point<int>(-1, -1));
/* Reserved a number of configurable children
* for memory efficiency
*/
/* Reserved a number of configurable children for memory efficiency */
void reserve_configurable_child(const ModuleId& module, const size_t& num_children);
/* Create a new configurable region under a module */
@ -283,10 +294,18 @@ class ModuleManager {
const ModuleId& child_module,
const size_t& child_instance,
const size_t& config_child_id);
/* Reserved a number of module nets for a given module
* for memory efficiency
/** @brief Add a I/O child to module
* This function also set the coordinate of a configurable child
* The coordinate is used for build I/O location map. So it is consistent with the VPR coordinate system
* By default, it is an invalid coordinate
*
* .. note:: I/O child does not necessary have to be a I/O block. It just provide a sequence for other functions, e.g., connect_gpio_module() to index the I/Os from each child module/instance.
*/
void add_io_child(const ModuleId& module, const ModuleId& child_module, const size_t& child_instance, const vtr::Point<int> coord = vtr::Point<int>(-1, -1));
/** @brief Reserved a number of I/O children for memory efficiency */
void reserve_io_child(const ModuleId& module, const size_t& num_children);
/* Reserved a number of module nets for a given module for memory efficiency */
void reserve_module_nets(const ModuleId& module, const size_t& num_nets);
/* Add a net to the connection graph of the module */
@ -295,9 +314,7 @@ class ModuleManager {
void set_net_name(const ModuleId& module, const ModuleNetId& net,
const std::string& name);
/* Reserved a number of sources for a module net for a given module
* for memory efficiency
*/
/* Reserved a number of sources for a module net for a given module for memory efficiency */
void reserve_module_net_sources(const ModuleId& module, const ModuleNetId& net,
const size_t& num_sources);
@ -306,9 +323,7 @@ class ModuleManager {
const ModuleId& src_module, const size_t& instance_id,
const ModulePortId& src_port, const size_t& src_pin);
/* Reserved a number of sinks for a module net for a given module
* for memory efficiency
*/
/* Reserved a number of sinks for a module net for a given module for memory efficiency */
void reserve_module_net_sinks(const ModuleId& module, const ModuleNetId& net,
const size_t& num_sinks);
@ -330,6 +345,14 @@ class ModuleManager {
* Do NOT use unless you know what you are doing!!!
*/
void clear_config_region(const ModuleId& parent_module);
/* This is a strong function which will remove all the io children
* under a given parent module
* It is mainly used by other functions which want to force an I/O sequence
* Do NOT use unless you know what you are doing!!!
*/
void clear_io_children(const ModuleId& parent_module);
public: /* Public validators/invalidators */
bool valid_module_id(const ModuleId& module) const;
bool valid_module_port_id(const ModuleId& module, const ModulePortId& port) const;
@ -371,6 +394,15 @@ class ModuleManager {
vtr::vector<ModuleId, vtr::vector<ConfigRegionId, ConfigRegionId>> config_region_ids_;
vtr::vector<ModuleId, vtr::vector<ConfigRegionId, std::vector<size_t>>> config_region_children_;
/* I/O child modules are used to record the position of I/O modules in GPIO indexing
* The sequence of children in the list denotes which one is indexed in the GPIO first, etc.
* Note that the sequence can be totally different from the children_ list
* This is really dependent how the I/O indexing is organized which should be made by users/designers
*/
vtr::vector<ModuleId, std::vector<ModuleId>> io_children_;
vtr::vector<ModuleId, std::vector<size_t>> io_child_instances_;
vtr::vector<ModuleId, std::vector<vtr::Point<int>>> io_child_coordinates_;
/* Port-level data */
vtr::vector<ModuleId, vtr::vector<ModulePortId, ModulePortId>> port_ids_; /* List of ports for each Module */
vtr::vector<ModuleId, vtr::vector<ModulePortId, BasicPort>> ports_; /* List of ports for each Module */

View File

@ -1802,39 +1802,37 @@ void add_module_io_ports_from_child_modules(ModuleManager& module_manager,
std::vector<BasicPort> gpio_ports_to_add;
std::vector<bool> mappable_gpio_ports;
/* Iterate over the child modules */
for (const ModuleId& child : module_manager.child_modules(module_id)) {
/* Iterate over the child instances */
for (size_t i = 0; i < module_manager.num_instance(module_id, child); ++i) {
/* Find all the global ports, whose port type is special */
for (const ModulePortId& gpio_port_id : module_manager.module_port_ids_by_type(child, module_port_type)) {
const BasicPort& gpio_port = module_manager.module_port(child, gpio_port_id);
/* If this port is not mergeable, we update the list */
bool is_mergeable = false;
for (size_t i_gpio_port_to_add = 0; i_gpio_port_to_add < gpio_ports_to_add.size(); ++i_gpio_port_to_add) {
BasicPort& gpio_port_to_add = gpio_ports_to_add[i_gpio_port_to_add];
if (false == gpio_port_to_add.mergeable(gpio_port)) {
continue;
}
is_mergeable = true;
/* Mappable I/O property must match! Mismatch rarely happened
* but should error out avoid silent bugs!
*/
VTR_ASSERT(module_manager.port_is_mappable_io(child, gpio_port_id) == mappable_gpio_ports[i_gpio_port_to_add]);
/* For mergeable ports, we combine the port
* Note: do NOT use the merge() method!
* the GPIO ports should be accumulated by the sizes of ports
* not by the LSB/MSB range !!!
*/
gpio_port_to_add.combine(gpio_port);
break;
}
if (false == is_mergeable) {
/* Reach here, this is an unique gpio port, update the list */
gpio_ports_to_add.push_back(gpio_port);
/* If the gpio port is a mappable I/O, we should herit from the child module */
mappable_gpio_ports.push_back(module_manager.port_is_mappable_io(child, gpio_port_id));
/* Iterate over the child modules and instances */
for (size_t i = 0; i < module_manager.io_children(module_id).size(); ++i) {
ModuleId child = module_manager.io_children(module_id)[i];
/* Find all the global ports, whose port type is special */
for (const ModulePortId& gpio_port_id : module_manager.module_port_ids_by_type(child, module_port_type)) {
const BasicPort& gpio_port = module_manager.module_port(child, gpio_port_id);
/* If this port is not mergeable, we update the list */
bool is_mergeable = false;
for (size_t i_gpio_port_to_add = 0; i_gpio_port_to_add < gpio_ports_to_add.size(); ++i_gpio_port_to_add) {
BasicPort& gpio_port_to_add = gpio_ports_to_add[i_gpio_port_to_add];
if (false == gpio_port_to_add.mergeable(gpio_port)) {
continue;
}
is_mergeable = true;
/* Mappable I/O property must match! Mismatch rarely happened
* but should error out avoid silent bugs!
*/
VTR_ASSERT(module_manager.port_is_mappable_io(child, gpio_port_id) == mappable_gpio_ports[i_gpio_port_to_add]);
/* For mergeable ports, we combine the port
* Note: do NOT use the merge() method!
* the GPIO ports should be accumulated by the sizes of ports
* not by the LSB/MSB range !!!
*/
gpio_port_to_add.combine(gpio_port);
break;
}
if (false == is_mergeable) {
/* Reach here, this is an unique gpio port, update the list */
gpio_ports_to_add.push_back(gpio_port);
/* If the gpio port is a mappable I/O, we should herit from the child module */
mappable_gpio_ports.push_back(module_manager.port_is_mappable_io(child, gpio_port_id));
}
}
}
@ -1854,49 +1852,47 @@ void add_module_io_ports_from_child_modules(ModuleManager& module_manager,
/* Set up a counter for each type of GPIO port */
std::vector<size_t> gpio_port_lsb(gpio_ports_to_add.size(), 0);
/* Add module nets to connect the GPIOs of the module to the GPIOs of the sub module */
for (const ModuleId& child : module_manager.child_modules(module_id)) {
/* Iterate over the child instances */
for (const size_t& child_instance : module_manager.child_module_instances(module_id, child)) {
/* Find all the global ports, whose port type is special */
for (ModulePortId child_gpio_port_id : module_manager.module_port_ids_by_type(child, module_port_type)) {
BasicPort child_gpio_port = module_manager.module_port(child, child_gpio_port_id);
/* Find the port with the same name! */
for (size_t iport = 0; iport < gpio_ports_to_add.size(); ++iport) {
if (false == gpio_ports_to_add[iport].mergeable(child_gpio_port)) {
continue;
}
/* For each pin of the child port, create a net and do wiring */
for (const size_t& pin_id : child_gpio_port.pins()) {
/* Reach here, it means this is the port we want, create a net and configure its source and sink */
/* - For GPIO and GPIN ports
* the source of the net is the current module
* the sink of the net is the child module
* - For GPOUT ports
* the source of the net is the child module
* the sink of the net is the current module
*/
if ( (ModuleManager::MODULE_GPIO_PORT == module_port_type)
|| (ModuleManager::MODULE_GPIN_PORT == module_port_type) ) {
ModuleNetId net = create_module_source_pin_net(module_manager, module_id, module_id, 0, gpio_port_ids[iport], gpio_port_lsb[iport]);
module_manager.add_module_net_sink(module_id, net, child, child_instance, child_gpio_port_id, pin_id);
} else {
VTR_ASSERT(ModuleManager::MODULE_GPOUT_PORT == module_port_type);
ModuleNetId net = create_module_source_pin_net(module_manager, module_id, child, child_instance, child_gpio_port_id, pin_id);
module_manager.add_module_net_sink(module_id, net, module_id, 0, gpio_port_ids[iport], gpio_port_lsb[iport]);
}
/* Update the LSB counter */
gpio_port_lsb[iport]++;
}
/* We finish for this child gpio port */
break;
for (size_t i = 0; i < module_manager.io_children(module_id).size(); ++i) {
ModuleId child = module_manager.io_children(module_id)[i];
size_t child_instance = module_manager.io_child_instances(module_id)[i];
/* Find all the global ports, whose port type is special */
for (ModulePortId child_gpio_port_id : module_manager.module_port_ids_by_type(child, module_port_type)) {
BasicPort child_gpio_port = module_manager.module_port(child, child_gpio_port_id);
/* Find the port with the same name! */
for (size_t iport = 0; iport < gpio_ports_to_add.size(); ++iport) {
if (false == gpio_ports_to_add[iport].mergeable(child_gpio_port)) {
continue;
}
/* For each pin of the child port, create a net and do wiring */
for (const size_t& pin_id : child_gpio_port.pins()) {
/* Reach here, it means this is the port we want, create a net and configure its source and sink */
/* - For GPIO and GPIN ports
* the source of the net is the current module
* the sink of the net is the child module
* - For GPOUT ports
* the source of the net is the child module
* the sink of the net is the current module
*/
if ( (ModuleManager::MODULE_GPIO_PORT == module_port_type)
|| (ModuleManager::MODULE_GPIN_PORT == module_port_type) ) {
ModuleNetId net = create_module_source_pin_net(module_manager, module_id, module_id, 0, gpio_port_ids[iport], gpio_port_lsb[iport]);
module_manager.add_module_net_sink(module_id, net, child, child_instance, child_gpio_port_id, pin_id);
} else {
VTR_ASSERT(ModuleManager::MODULE_GPOUT_PORT == module_port_type);
ModuleNetId net = create_module_source_pin_net(module_manager, module_id, child, child_instance, child_gpio_port_id, pin_id);
module_manager.add_module_net_sink(module_id, net, module_id, 0, gpio_port_ids[iport], gpio_port_lsb[iport]);
}
/* Update the LSB counter */
gpio_port_lsb[iport]++;
}
/* We finish for this child gpio port */
break;
}
}
}
/* Check: all the lsb should now match the size of each GPIO port */
for (size_t iport = 0; iport < gpio_ports_to_add.size(); ++iport) {
if (gpio_ports_to_add[iport].get_width() != gpio_port_lsb[iport])
VTR_ASSERT(gpio_ports_to_add[iport].get_width() == gpio_port_lsb[iport]);
}
}