[Tool] Add mappable I/O support and enhance I/O support
This commit is contained in:
parent
dd86f7f464
commit
37c10f0cb5
|
@ -571,31 +571,41 @@ static
|
|||
size_t check_io_circuit_model(const CircuitLibrary& circuit_lib) {
|
||||
size_t num_err = 0;
|
||||
|
||||
/* Embedded I/O interface may not have inout port
|
||||
* iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_INOUT);
|
||||
* Some I/Os may not have SRAM port, such as AIB interface
|
||||
* iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_SRAM);
|
||||
*/
|
||||
std::vector<enum e_circuit_model_port_type> iopad_port_types_required;
|
||||
iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_INOUT);
|
||||
num_err += check_circuit_model_port_required(circuit_lib, CIRCUIT_MODEL_IOPAD, iopad_port_types_required);
|
||||
|
||||
/* Each I/O cell must have
|
||||
* - One of the following ports
|
||||
* - At least 1 ASIC-to-FPGA (A2F) port that is defined as global I/O
|
||||
* - At least 1 FPGA-to-ASIC (F2A) port that is defined as global I/O!
|
||||
* - At least 1 ASIC-to-FPGA (A2F) port that is defined as global data I/O
|
||||
* - At least 1 FPGA-to-ASIC (F2A) port that is defined as global data I/O!
|
||||
* - At least 1 regular port that is non-global which is connected to global routing architecture
|
||||
*/
|
||||
for (const auto& io_model : circuit_lib.models_by_type(CIRCUIT_MODEL_IOPAD)) {
|
||||
bool has_global_io = false;
|
||||
bool has_data_io = false;
|
||||
bool has_data_input_only_io = false;
|
||||
bool has_data_output_only_io = false;
|
||||
bool has_internal_connection = false;
|
||||
|
||||
for (const auto& port : circuit_lib.model_ports(io_model)) {
|
||||
if ( (true == circuit_lib.port_is_io(port)
|
||||
&& (true == circuit_lib.port_is_global(port)))) {
|
||||
has_global_io = true;
|
||||
if ( (true == circuit_lib.port_is_io(port))
|
||||
&& (true == circuit_lib.port_is_data_io(port))
|
||||
&& (CIRCUIT_MODEL_PORT_INOUT == circuit_lib.port_type(port))
|
||||
&& (true == circuit_lib.port_is_global(port))) {
|
||||
has_data_io = true;
|
||||
continue; /* Go to next */
|
||||
}
|
||||
if ( (true == circuit_lib.port_is_io(port))
|
||||
&& (true == circuit_lib.port_is_data_io(port))
|
||||
&& (CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(port))
|
||||
&& (true == circuit_lib.port_is_global(port))) {
|
||||
has_data_input_only_io = true;
|
||||
continue; /* Go to next */
|
||||
}
|
||||
if ( (true == circuit_lib.port_is_io(port))
|
||||
&& (true == circuit_lib.port_is_data_io(port))
|
||||
&& (CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port))
|
||||
&& (true == circuit_lib.port_is_global(port))) {
|
||||
has_data_output_only_io = true;
|
||||
continue; /* Go to next */
|
||||
}
|
||||
|
||||
if ( (false == circuit_lib.port_is_io(port)
|
||||
&& (false == circuit_lib.port_is_global(port)))
|
||||
&& (CIRCUIT_MODEL_PORT_SRAM != circuit_lib.port_type(port))) {
|
||||
|
@ -604,9 +614,14 @@ size_t check_io_circuit_model(const CircuitLibrary& circuit_lib) {
|
|||
}
|
||||
}
|
||||
|
||||
if (false == has_global_io) {
|
||||
/* Error out when
|
||||
* - there is no data io, data input-only io and data output-only io
|
||||
*/
|
||||
if ( (false == has_data_io)
|
||||
&& (false == has_data_input_only_io)
|
||||
&& (false == has_data_output_only_io)) {
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"I/O circuit model '%s' does not have any I/O port defined!\n",
|
||||
"I/O circuit model '%s' does not have any data I/O port defined!\n",
|
||||
circuit_lib.model_name(io_model).c_str());
|
||||
num_err++;
|
||||
}
|
||||
|
|
|
@ -907,6 +907,13 @@ bool CircuitLibrary::port_is_io(const CircuitPortId& circuit_port_id) const {
|
|||
return port_is_io_[circuit_port_id];
|
||||
}
|
||||
|
||||
/* Return a flag if the port is used in mode-selection purpuse of a circuit model */
|
||||
bool CircuitLibrary::port_is_data_io(const CircuitPortId& circuit_port_id) const {
|
||||
/* validate the circuit_port_id */
|
||||
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||
return port_is_data_io_[circuit_port_id];
|
||||
}
|
||||
|
||||
/* Return a flag if the port is used in mode-selection purpuse of a circuit model */
|
||||
bool CircuitLibrary::port_is_mode_select(const CircuitPortId& circuit_port_id) const {
|
||||
/* validate the circuit_port_id */
|
||||
|
@ -1370,6 +1377,7 @@ CircuitPortId CircuitLibrary::add_model_port(const CircuitModelId& model_id,
|
|||
port_inv_prefix_.emplace_back();
|
||||
port_default_values_.push_back(-1);
|
||||
port_is_io_.push_back(false);
|
||||
port_is_data_io_.push_back(false);
|
||||
port_is_mode_select_.push_back(false);
|
||||
port_is_global_.push_back(false);
|
||||
port_is_reset_.push_back(false);
|
||||
|
@ -1449,6 +1457,15 @@ void CircuitLibrary::set_port_is_io(const CircuitPortId& circuit_port_id,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Set the is_mode_select for a port of a circuit model */
|
||||
void CircuitLibrary::set_port_is_data_io(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_data_io) {
|
||||
/* validate the circuit_port_id */
|
||||
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||
port_is_data_io_[circuit_port_id] = is_data_io;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the is_mode_select for a port of a circuit model */
|
||||
void CircuitLibrary::set_port_is_mode_select(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_mode_select) {
|
||||
|
|
|
@ -79,27 +79,29 @@
|
|||
* 2. pass_gate_logic_model_id_: specify the id of circuit model for the pass gate logic
|
||||
*
|
||||
* ------ Port information ------
|
||||
* 1. port_ids_: unique id of ports belonging to a circuit model
|
||||
* 1. port_model_ids_: unique id of the parent circuit model for the port
|
||||
* 2. port_types_: types of ports belonging to a circuit model
|
||||
* 3. port_sizes_: width of ports belonging to a circuit model
|
||||
* 4. port_prefix_: prefix of a port when instance of a circuit model
|
||||
* 5. port_lib_names_: port name in the standard cell library, only used when explicit_port_mapping is enabled
|
||||
* 6. port_inv_prefix_: the prefix to be added for the inverted port. This is mainly used by SRAM ports, which have an coupled inverterd port
|
||||
* 7. port_is_mode_select: specify if this port is used to select operating modes of the circuit model
|
||||
* 8. port_is_global: specify if this port is a global signal shared by other circuit model
|
||||
* 9. port_is_reset: specify if this port is a reset signal which needs special pulse widths in testbenches
|
||||
* 10. port_is_set: specify if this port is a set signal which needs special pulse widths in testbenches
|
||||
* 11. port_is_config_enable: specify if this port is a config_enable signal which needs special pulse widths in testbenches
|
||||
* 12. port_is_prog: specify if this port is for FPGA programming use which needs special pulse widths in testbenches
|
||||
* 13. port_tri_state_model_name: the name of circuit model linked to tri-state the port
|
||||
* 14. port_tri_state_model_ids_: the Id of circuit model linked to tri-state the port
|
||||
* 15. port_inv_model_names_: the name of inverter circuit model linked to the port
|
||||
* 16. port_inv_model_ids_: the Id of inverter circuit model linked to the port
|
||||
* 17. port_tri_state_map_: only applicable to inputs of LUTs, the tri-state map applied to each pin of this port
|
||||
* 18. port_lut_frac_level_: only applicable to outputs of LUTs, indicate which level of outputs inside LUT multiplexing structure will be used
|
||||
* 19. port_lut_output_mask_: only applicable to outputs of LUTs, indicate which output at an internal level of LUT multiplexing structure will be used
|
||||
* 20. port_sram_orgz_: only applicable to SRAM ports, indicate how the SRAMs will be organized, either memory decoders or scan-chains
|
||||
* - port_ids_: unique id of ports belonging to a circuit model
|
||||
* - port_model_ids_: unique id of the parent circuit model for the port
|
||||
* - port_types_: types of ports belonging to a circuit model
|
||||
* - port_sizes_: width of ports belonging to a circuit model
|
||||
* - port_prefix_: prefix of a port when instance of a circuit model
|
||||
* - port_lib_names_: port name in the standard cell library, only used when explicit_port_mapping is enabled
|
||||
* - port_inv_prefix_: the prefix to be added for the inverted port. This is mainly used by SRAM ports, which have an coupled inverterd port
|
||||
* - port_is_mode_select: specify if this port is used to select operating modes of the circuit model
|
||||
* - port_is_io: specify if this port is an io port
|
||||
* - port_is_data_io: specify if this port is an io port that can be mapped to a signal from netlist
|
||||
* - port_is_global: specify if this port is a global signal shared by other circuit model
|
||||
* - port_is_reset: specify if this port is a reset signal which needs special pulse widths in testbenches
|
||||
* - port_is_set: specify if this port is a set signal which needs special pulse widths in testbenches
|
||||
* - port_is_config_enable: specify if this port is a config_enable signal which needs special pulse widths in testbenches
|
||||
* - port_is_prog: specify if this port is for FPGA programming use which needs special pulse widths in testbenches
|
||||
* - port_tri_state_model_name: the name of circuit model linked to tri-state the port
|
||||
* - port_tri_state_model_ids_: the Id of circuit model linked to tri-state the port
|
||||
* - port_inv_model_names_: the name of inverter circuit model linked to the port
|
||||
* - port_inv_model_ids_: the Id of inverter circuit model linked to the port
|
||||
* - port_tri_state_map_: only applicable to inputs of LUTs, the tri-state map applied to each pin of this port
|
||||
* - port_lut_frac_level_: only applicable to outputs of LUTs, indicate which level of outputs inside LUT multiplexing structure will be used
|
||||
* - port_lut_output_mask_: only applicable to outputs of LUTs, indicate which output at an internal level of LUT multiplexing structure will be used
|
||||
* - port_sram_orgz_: only applicable to SRAM ports, indicate how the SRAMs will be organized, either memory decoders or scan-chains
|
||||
*
|
||||
* ------ Delay information ------
|
||||
* 1. delay_types_: type of pin-to-pin delay, either rising_edge of falling_edge
|
||||
|
@ -279,6 +281,7 @@ class CircuitLibrary {
|
|||
std::string port_inv_prefix(const CircuitPortId& circuit_port_id) const;
|
||||
size_t port_default_value(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_io(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_data_io(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_mode_select(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_global(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_reset(const CircuitPortId& circuit_port_id) const;
|
||||
|
@ -354,6 +357,8 @@ class CircuitLibrary {
|
|||
const size_t& default_val);
|
||||
void set_port_is_io(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_io);
|
||||
void set_port_is_data_io(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_data_io);
|
||||
void set_port_is_mode_select(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_mode_select);
|
||||
void set_port_is_global(const CircuitPortId& circuit_port_id,
|
||||
|
@ -545,6 +550,7 @@ class CircuitLibrary {
|
|||
vtr::vector<CircuitPortId, std::string> port_inv_prefix_;
|
||||
vtr::vector<CircuitPortId, size_t> port_default_values_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_io_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_data_io_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_mode_select_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_global_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_reset_;
|
||||
|
|
|
@ -418,6 +418,13 @@ void read_xml_circuit_port(pugi::xml_node& xml_port,
|
|||
*/
|
||||
circuit_lib.set_port_is_io(port, get_attribute(xml_port, "is_io", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
|
||||
|
||||
/* Identify if the port is a data io, ONLY applicable to I/O port
|
||||
* By default, it will NOT be a data io port
|
||||
*/
|
||||
if (true == circuit_lib.port_is_io(port)) {
|
||||
circuit_lib.set_port_is_data_io(port, get_attribute(xml_port, "is_data_io", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
|
||||
}
|
||||
|
||||
/* Identify if the port is for mode selection, this is only applicable to SRAM ports.
|
||||
* By default, it will NOT be a mode selection port
|
||||
*/
|
||||
|
|
|
@ -186,6 +186,15 @@ void write_xml_circuit_port(std::fstream& fp,
|
|||
}
|
||||
}
|
||||
|
||||
/* I/O port attributes */
|
||||
if (true == circuit_lib.port_is_io(port)) {
|
||||
write_xml_attribute(fp, "is_io", "true");
|
||||
}
|
||||
|
||||
if (true == circuit_lib.port_is_data_io(port)) {
|
||||
write_xml_attribute(fp, "is_data_io", "true");
|
||||
}
|
||||
|
||||
/* Global, reset, set port attributes */
|
||||
if (true == circuit_lib.port_is_global(port)) {
|
||||
write_xml_attribute(fp, "is_global", "true");
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "openfpga_reserved_words.h"
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
#include "module_manager_utils.h"
|
||||
#include "openfpga_device_grid_utils.h"
|
||||
#include "build_fabric_io_location_map.h"
|
||||
|
||||
|
@ -74,7 +75,15 @@ IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager,
|
|||
* 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 BasicPort& gpio_port : module_manager.module_ports_by_type(grid_module, ModuleManager::MODULE_GPIO_PORT)) {
|
||||
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()) {
|
||||
|
@ -88,15 +97,24 @@ IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager,
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 BasicPort& gpio_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)) {
|
||||
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;
|
||||
}
|
||||
|
||||
const BasicPort& gpio_port = module_manager.module_port(top_module, gpio_port_id);
|
||||
VTR_ASSERT(io_counter[gpio_port.get_name()] == gpio_port.get_width());
|
||||
}
|
||||
}
|
||||
|
||||
return io_location_map;
|
||||
}
|
||||
|
|
|
@ -286,6 +286,12 @@ size_t ModuleManager::instance_id(const ModuleId& parent_module, const ModuleId&
|
|||
return size_t(-1);
|
||||
}
|
||||
|
||||
ModuleManager::e_module_port_type ModuleManager::port_type(const ModuleId& module, const ModulePortId& port) const {
|
||||
/* validate both module id and port id*/
|
||||
VTR_ASSERT(valid_module_port_id(module, port));
|
||||
return port_types_[module][port];
|
||||
}
|
||||
|
||||
/* Find if a port is a wire connection */
|
||||
bool ModuleManager::port_is_wire(const ModuleId& module, const ModulePortId& port) const {
|
||||
/* validate both module id and port id*/
|
||||
|
@ -293,6 +299,13 @@ bool ModuleManager::port_is_wire(const ModuleId& module, const ModulePortId& por
|
|||
return port_is_wire_[module][port];
|
||||
}
|
||||
|
||||
/* Find if a port is a mappable i/o */
|
||||
bool ModuleManager::port_is_mappable_io(const ModuleId& module, const ModulePortId& port) const {
|
||||
/* validate both module id and port id*/
|
||||
VTR_ASSERT(valid_module_port_id(module, port));
|
||||
return port_is_mappable_io_[module][port];
|
||||
}
|
||||
|
||||
/* Find if a port is register */
|
||||
bool ModuleManager::port_is_register(const ModuleId& module, const ModulePortId& port) const {
|
||||
/* validate both module id and port id*/
|
||||
|
@ -529,6 +542,7 @@ ModuleId ModuleManager::add_module(const std::string& name) {
|
|||
ports_.emplace_back();
|
||||
port_types_.emplace_back();
|
||||
port_is_wire_.emplace_back();
|
||||
port_is_mappable_io_.emplace_back();
|
||||
port_is_register_.emplace_back();
|
||||
port_preproc_flags_.emplace_back();
|
||||
|
||||
|
@ -573,6 +587,7 @@ ModulePortId ModuleManager::add_port(const ModuleId& module,
|
|||
ports_[module].push_back(port_info);
|
||||
port_types_[module].push_back(port_type);
|
||||
port_is_wire_[module].push_back(false);
|
||||
port_is_mappable_io_[module].push_back(false);
|
||||
port_is_register_[module].push_back(false);
|
||||
port_preproc_flags_[module].emplace_back(); /* Create an empty string for the pre-processing flags */
|
||||
|
||||
|
@ -617,6 +632,13 @@ void ModuleManager::set_port_is_wire(const ModuleId& module, const std::string&
|
|||
port_is_wire_[module][port] = is_wire;
|
||||
}
|
||||
|
||||
/* Set a port to be a mappable I/O */
|
||||
void ModuleManager::set_port_is_mappable_io(const ModuleId& module, const ModulePortId& port_id, const bool& is_mappable_io) {
|
||||
/* Must find something, otherwise drop an error */
|
||||
VTR_ASSERT(valid_module_port_id(module, port_id));
|
||||
port_is_mappable_io_[module][port_id] = is_mappable_io;
|
||||
}
|
||||
|
||||
/* Set a port to be a register */
|
||||
void ModuleManager::set_port_is_register(const ModuleId& module, const std::string& port_name, const bool& is_register) {
|
||||
/* Find the port */
|
||||
|
|
|
@ -184,8 +184,12 @@ class ModuleManager {
|
|||
/* Find the instance id of a given instance name */
|
||||
size_t instance_id(const ModuleId& parent_module, const ModuleId& child_module,
|
||||
const std::string& instance_name) const;
|
||||
/* Find the type of a port */
|
||||
ModuleManager::e_module_port_type port_type(const ModuleId& module, const ModulePortId& port) const;
|
||||
/* Find if a port is a wire connection */
|
||||
bool port_is_wire(const ModuleId& module, const ModulePortId& port) const;
|
||||
/* Find if a port is mappable to an I/O from users' implementations */
|
||||
bool port_is_mappable_io(const ModuleId& module, const ModulePortId& port) const;
|
||||
/* Find if a port is register */
|
||||
bool port_is_register(const ModuleId& module, const ModulePortId& port) const;
|
||||
/* Return the pre-processing flag of a port */
|
||||
|
@ -238,6 +242,8 @@ class ModuleManager {
|
|||
void set_module_usage(const ModuleId& module, const e_module_usage_type& usage);
|
||||
/* Set a port to be a wire */
|
||||
void set_port_is_wire(const ModuleId& module, const std::string& port_name, const bool& is_wire);
|
||||
/* Set a port to be mappable to an I/O from users' implemenations */
|
||||
void set_port_is_mappable_io(const ModuleId& module, const ModulePortId& port_id, const bool& is_mappable_io);
|
||||
/* Set a port to be a register */
|
||||
void set_port_is_register(const ModuleId& module, const std::string& port_name, const bool& is_register);
|
||||
/* Set the preprocessing flag for a port */
|
||||
|
@ -356,6 +362,7 @@ class ModuleManager {
|
|||
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 */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, enum e_module_port_type>> port_types_; /* Type of ports */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, bool>> port_is_mappable_io_; /* If the port is mappable to an I/O for user's implementations */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, bool>> port_is_wire_; /* If the port is a wire, use for Verilog port definition. If enabled: <port_type> reg <port_name> */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, bool>> port_is_register_; /* If the port is a register, use for Verilog port definition. If enabled: <port_type> reg <port_name> */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, std::string>> port_preproc_flags_; /* If a port is available only when a pre-processing flag is enabled. This is to record the pre-processing flags */
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*******************************************************************/
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
|
@ -17,6 +18,8 @@
|
|||
|
||||
#include "verilog_port_types.h"
|
||||
|
||||
#include "module_manager_utils.h"
|
||||
|
||||
#include "verilog_constants.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_testbench_utils.h"
|
||||
|
@ -147,12 +150,29 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp,
|
|||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* In this function, we support only 1 type of I/Os */
|
||||
std::vector<BasicPort> module_io_ports = module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep tracking which I/Os have been used */
|
||||
for (const BasicPort& module_io_port : module_io_ports) {
|
||||
std::vector<bool> io_used(module_io_port.get_width(), false);
|
||||
std::map<ModulePortId, std::vector<bool>> io_used;
|
||||
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);
|
||||
io_used[module_io_port_id] = std::vector<bool>(module_io_port.get_width(), false);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* See if this I/O should be wired to a benchmark input/output */
|
||||
/* Add signals from blif benchmark and short-wire them to FPGA I/O PADs
|
||||
|
@ -167,19 +187,46 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp,
|
|||
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 io_index = io_location_map.io_index(place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.x,
|
||||
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.z,
|
||||
module_io_port.get_name());
|
||||
|
||||
/* Bypass invalid index (not mapped to this GPIO port) */
|
||||
if (size_t(-1) == io_index) {
|
||||
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_io_port;
|
||||
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);
|
||||
|
@ -209,22 +256,23 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp,
|
|||
}
|
||||
|
||||
/* Mark this I/O has been used/wired */
|
||||
io_used[io_index] = true;
|
||||
}
|
||||
io_used[mapped_module_io_info.first][io_index] = true;
|
||||
|
||||
/* Add an empty line as a splitter */
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/* Wire the unused iopads to a constant */
|
||||
print_verilog_comment(fp, std::string("----- Wire unused FPGA I/Os to constants -----"));
|
||||
for (size_t io_index = 0; io_index < io_used.size(); ++io_index) {
|
||||
for (const ModulePortId& module_io_port_id : module_io_ports) {
|
||||
for (size_t io_index = 0; io_index < io_used[module_io_port_id].size(); ++io_index) {
|
||||
/* Bypass used iopads */
|
||||
if (true == io_used[io_index]) {
|
||||
if (true == io_used[module_io_port_id][io_index]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Wire to a contant */
|
||||
BasicPort module_unused_io_port = module_io_port;
|
||||
BasicPort module_unused_io_port = module_manager.module_port(top_module, module_io_port_id);
|
||||
/* Set the port pin index */
|
||||
module_unused_io_port.set_width(io_index, io_index);
|
||||
|
||||
|
|
|
@ -191,7 +191,11 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
|
|||
for (const auto& kv : port_type2type_map) {
|
||||
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, kv.first, true)) {
|
||||
BasicPort port_info(circuit_lib.port_prefix(port), circuit_lib.port_size(port));
|
||||
module_manager.add_port(module, port_info, kv.second);
|
||||
ModulePortId module_port = module_manager.add_port(module, port_info, kv.second);
|
||||
/* Specify if the port can be mapped to an data signal */
|
||||
if (true == circuit_lib.port_is_data_io(port)) {
|
||||
module_manager.set_port_is_mappable_io(module, module_port, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1454,20 +1458,27 @@ void add_module_io_ports_from_child_modules(ModuleManager& module_manager,
|
|||
const ModuleId& module_id,
|
||||
const ModuleManager::e_module_port_type& module_port_type) {
|
||||
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 (BasicPort gpio_port : module_manager.module_ports_by_type(child, module_port_type)) {
|
||||
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 (BasicPort& gpio_port_to_add : gpio_ports_to_add) {
|
||||
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
|
||||
|
@ -1479,6 +1490,8 @@ void add_module_io_ports_from_child_modules(ModuleManager& module_manager,
|
|||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1487,9 +1500,13 @@ void add_module_io_ports_from_child_modules(ModuleManager& module_manager,
|
|||
/* Record the port id for each type of GPIO port */
|
||||
std::vector<ModulePortId> gpio_port_ids;
|
||||
/* Add the gpio ports for the module */
|
||||
for (const BasicPort& gpio_port_to_add : gpio_ports_to_add) {
|
||||
for (size_t iport = 0; iport < gpio_ports_to_add.size(); ++iport) {
|
||||
const BasicPort& gpio_port_to_add = gpio_ports_to_add[iport];
|
||||
ModulePortId port_id = module_manager.add_port(module_id, gpio_port_to_add, module_port_type);
|
||||
gpio_port_ids.push_back(port_id);
|
||||
if (true == mappable_gpio_ports[iport]) {
|
||||
module_manager.set_port_is_mappable_io(module_id, port_id, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up a counter for each type of GPIO port */
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
constexpr std::array<ModuleManager::e_module_port_type, 3> MODULE_IO_PORT_TYPES = {ModuleManager::MODULE_GPIN_PORT, ModuleManager::MODULE_GPOUT_PORT, ModuleManager::MODULE_GPIO_PORT};
|
||||
|
||||
void reserve_module_manager_module_nets(ModuleManager& module_manager,
|
||||
const ModuleId& module);
|
||||
|
||||
|
|
Loading…
Reference in New Issue