179 lines
6.8 KiB
C++
179 lines
6.8 KiB
C++
/********************************************************************
|
|
* This file includes functions that build io mapping information
|
|
*******************************************************************/
|
|
#include <chrono>
|
|
#include <ctime>
|
|
#include <fstream>
|
|
|
|
/* Headers from vtrutil library */
|
|
#include "vtr_assert.h"
|
|
#include "vtr_log.h"
|
|
#include "vtr_time.h"
|
|
|
|
/* Headers from archopenfpga library */
|
|
#include "build_io_mapping_info.h"
|
|
#include "module_manager_utils.h"
|
|
#include "openfpga_naming.h"
|
|
|
|
/* begin namespace openfpga */
|
|
namespace openfpga {
|
|
|
|
/********************************************************************
|
|
* This function
|
|
* - builds the net-to-I/O mapping
|
|
* - identifies each I/O directionality
|
|
* - return a database containing the above information
|
|
*
|
|
* TODO: This function duplicates codes from
|
|
* function: print_verilog_testbench_connect_fpga_ios() in
|
|
* source file: verilog_testbench_utils.cpp
|
|
* Should consider how to merge the codes and share same builder function
|
|
*******************************************************************/
|
|
IoMap build_fpga_io_mapping_info(
|
|
const ModuleManager& module_manager, const ModuleId& top_module,
|
|
const AtomContext& atom_ctx, const PlacementContext& place_ctx,
|
|
const IoLocationMap& io_location_map,
|
|
const VprNetlistAnnotation& netlist_annotation,
|
|
const std::string& io_input_port_name_postfix,
|
|
const std::string& io_output_port_name_postfix,
|
|
const std::vector<std::string>& output_port_prefix_to_remove) {
|
|
IoMap io_map;
|
|
|
|
/* Only mappable i/o ports can be considered */
|
|
std::vector<ModulePortId> module_io_ports;
|
|
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 */
|
|
if (false ==
|
|
module_manager.port_is_mappable_io(top_module, gpio_port_id)) {
|
|
continue;
|
|
}
|
|
module_io_ports.push_back(gpio_port_id);
|
|
}
|
|
}
|
|
|
|
/* Type mapping between VPR block and Module port */
|
|
std::map<AtomBlockType, ModuleManager::e_module_port_type>
|
|
atom_block_type_to_module_port_type;
|
|
atom_block_type_to_module_port_type[AtomBlockType::INPAD] =
|
|
ModuleManager::MODULE_GPIN_PORT;
|
|
atom_block_type_to_module_port_type[AtomBlockType::OUTPAD] =
|
|
ModuleManager::MODULE_GPOUT_PORT;
|
|
|
|
/* Type mapping between VPR block and io mapping direction */
|
|
std::map<AtomBlockType, IoMap::e_direction>
|
|
atom_block_type_to_io_map_direction;
|
|
atom_block_type_to_io_map_direction[AtomBlockType::INPAD] =
|
|
IoMap::IO_MAP_DIR_INPUT;
|
|
atom_block_type_to_io_map_direction[AtomBlockType::OUTPAD] =
|
|
IoMap::IO_MAP_DIR_OUTPUT;
|
|
|
|
for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) {
|
|
/* Bypass non-I/O atom blocks ! */
|
|
if ((AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk)) &&
|
|
(AtomBlockType::OUTPAD != atom_ctx.nlist.block_type(atom_blk))) {
|
|
continue;
|
|
}
|
|
|
|
/* If there is a GPIO port, use it directly
|
|
* Otherwise, should find a GPIN for INPAD
|
|
* or should find a GPOUT for OUTPAD
|
|
*/
|
|
std::pair<ModulePortId, size_t> mapped_module_io_info =
|
|
std::make_pair(ModulePortId::INVALID(), -1);
|
|
for (const ModulePortId& module_io_port_id : module_io_ports) {
|
|
const BasicPort& module_io_port =
|
|
module_manager.module_port(top_module, module_io_port_id);
|
|
|
|
/* Find the index of the mapped GPIO in top-level FPGA fabric */
|
|
size_t temp_io_index = io_location_map.io_index(
|
|
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.x,
|
|
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.y,
|
|
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.sub_tile,
|
|
module_io_port.get_name());
|
|
|
|
/* Bypass invalid index (not mapped to this GPIO port) */
|
|
if (size_t(-1) == temp_io_index) {
|
|
continue;
|
|
}
|
|
|
|
/* If the port is an GPIO port, just use it */
|
|
if (ModuleManager::MODULE_GPIO_PORT ==
|
|
module_manager.port_type(top_module, module_io_port_id)) {
|
|
mapped_module_io_info =
|
|
std::make_pair(module_io_port_id, temp_io_index);
|
|
break;
|
|
}
|
|
|
|
/* If this is an INPAD, we can use an GPIN port (if available) */
|
|
if (atom_block_type_to_module_port_type[atom_ctx.nlist.block_type(
|
|
atom_blk)] ==
|
|
module_manager.port_type(top_module, module_io_port_id)) {
|
|
mapped_module_io_info =
|
|
std::make_pair(module_io_port_id, temp_io_index);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* We must find a valid one */
|
|
VTR_ASSERT(true == module_manager.valid_module_port_id(
|
|
top_module, mapped_module_io_info.first));
|
|
VTR_ASSERT(size_t(-1) != mapped_module_io_info.second);
|
|
|
|
/* Ensure that IO index is in range */
|
|
BasicPort module_mapped_io_port =
|
|
module_manager.module_port(top_module, mapped_module_io_info.first);
|
|
size_t io_index = mapped_module_io_info.second;
|
|
|
|
/* Set the port pin index */
|
|
VTR_ASSERT(io_index < module_mapped_io_port.get_width());
|
|
module_mapped_io_port.set_width(io_index, io_index);
|
|
|
|
/* The block may be renamed as it contains special characters which violate
|
|
* Verilog syntax */
|
|
std::string block_name = atom_ctx.nlist.block_name(atom_blk);
|
|
if (true == netlist_annotation.is_block_renamed(atom_blk)) {
|
|
block_name = netlist_annotation.block_name(atom_blk);
|
|
}
|
|
|
|
/* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always
|
|
* has a size of 1 In addition, the input and output ports may have
|
|
* different postfix in naming due to verification context! Here, we give
|
|
* full customization on naming
|
|
*/
|
|
BasicPort benchmark_io_port;
|
|
if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) {
|
|
benchmark_io_port.set_name(
|
|
std::string(block_name + io_input_port_name_postfix));
|
|
benchmark_io_port.set_width(1);
|
|
} else {
|
|
VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk));
|
|
/* VPR may have added a prefix to the output ports, remove them here */
|
|
std::string output_block_name = block_name;
|
|
for (const std::string& prefix_to_remove : output_port_prefix_to_remove) {
|
|
if (!prefix_to_remove.empty()) {
|
|
if (0 == output_block_name.find(prefix_to_remove)) {
|
|
output_block_name.erase(0, prefix_to_remove.length());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
benchmark_io_port.set_name(
|
|
std::string(output_block_name + io_output_port_name_postfix));
|
|
benchmark_io_port.set_width(1);
|
|
}
|
|
|
|
io_map.create_io_mapping(
|
|
module_mapped_io_port, benchmark_io_port,
|
|
atom_block_type_to_io_map_direction[atom_ctx.nlist.block_type(atom_blk)]);
|
|
}
|
|
|
|
return io_map;
|
|
}
|
|
|
|
} /* end namespace openfpga */
|