[engine] now support a custom list for indexing I/O children in each module
This commit is contained in:
parent
ec38b3990f
commit
cb89488f76
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
******************************************************************************/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue