2592 lines
112 KiB
C++
2592 lines
112 KiB
C++
/******************************************************************************
|
|
* This files includes most utilized functions
|
|
* for data structures for module management.
|
|
******************************************************************************/
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <map>
|
|
|
|
/* Headers from vtrutil library */
|
|
#include "command_exit_codes.h"
|
|
#include "vtr_assert.h"
|
|
#include "vtr_log.h"
|
|
|
|
/* Headers from openfpgautil library */
|
|
#include "build_decoder_modules.h"
|
|
#include "circuit_library_utils.h"
|
|
#include "decoder_library_utils.h"
|
|
#include "memory_utils.h"
|
|
#include "module_manager_utils.h"
|
|
#include "openfpga_naming.h"
|
|
#include "openfpga_port.h"
|
|
#include "openfpga_reserved_words.h"
|
|
#include "pb_type_utils.h"
|
|
|
|
/* begin namespace openfpga */
|
|
namespace openfpga {
|
|
|
|
/******************************************************************************
|
|
* Reserved a number of module nets for a given module
|
|
* based on the number of output ports of its child modules
|
|
* for memory efficiency
|
|
******************************************************************************/
|
|
void reserve_module_manager_module_nets(ModuleManager& module_manager,
|
|
const ModuleId& parent_module) {
|
|
size_t num_nets = 0;
|
|
|
|
/* Collect the driver port types for parent module*/
|
|
std::vector<ModuleManager::e_module_port_type> driver_port_types;
|
|
driver_port_types.push_back(ModuleManager::MODULE_GLOBAL_PORT);
|
|
driver_port_types.push_back(ModuleManager::MODULE_GPIN_PORT);
|
|
driver_port_types.push_back(ModuleManager::MODULE_GPIO_PORT);
|
|
driver_port_types.push_back(ModuleManager::MODULE_INOUT_PORT);
|
|
driver_port_types.push_back(ModuleManager::MODULE_INPUT_PORT);
|
|
driver_port_types.push_back(ModuleManager::MODULE_CLOCK_PORT);
|
|
|
|
/* The number of nets depends on the sizes of input ports of parent module */
|
|
for (const auto& port_type : driver_port_types) {
|
|
for (const BasicPort& port :
|
|
module_manager.module_ports_by_type(parent_module, port_type)) {
|
|
num_nets += port.get_width();
|
|
}
|
|
}
|
|
|
|
/* Collect the output port types */
|
|
std::vector<ModuleManager::e_module_port_type> output_port_types;
|
|
output_port_types.push_back(ModuleManager::MODULE_GPOUT_PORT);
|
|
output_port_types.push_back(ModuleManager::MODULE_OUTPUT_PORT);
|
|
|
|
for (const ModuleId& child_module :
|
|
module_manager.child_modules(parent_module)) {
|
|
/* The number of nets depends on the sizes of output ports of
|
|
* each instanciated child module
|
|
*/
|
|
size_t num_instances =
|
|
module_manager.num_instance(parent_module, child_module);
|
|
|
|
/* Sum up the port sizes for all the output ports */
|
|
size_t total_output_port_sizes = 0;
|
|
for (const auto& port_type : output_port_types) {
|
|
for (const BasicPort& port :
|
|
module_manager.module_ports_by_type(child_module, port_type)) {
|
|
total_output_port_sizes += port.get_width();
|
|
}
|
|
}
|
|
|
|
num_nets += total_output_port_sizes * num_instances;
|
|
}
|
|
|
|
module_manager.reserve_module_nets(parent_module, num_nets);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Count the 'actual' number of configurable children for a module in module
|
|
*manager A 'true' configurable children should have a number of configurable
|
|
*children as well
|
|
******************************************************************************/
|
|
size_t count_module_manager_module_configurable_children(
|
|
const ModuleManager& module_manager, const ModuleId& module,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
size_t num_config_children = 0;
|
|
|
|
for (const ModuleId& child :
|
|
module_manager.configurable_children(module, config_child_type)) {
|
|
if (0 !=
|
|
module_manager.configurable_children(child, config_child_type).size()) {
|
|
num_config_children++;
|
|
}
|
|
}
|
|
|
|
return num_config_children;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Find the module id and instance id in module manager with a given instance
|
|
*name This function will exhaustively search all the child module under a given
|
|
*parent module
|
|
******************************************************************************/
|
|
std::pair<ModuleId, size_t> find_module_manager_instance_module_info(
|
|
const ModuleManager& module_manager, const ModuleId& parent,
|
|
const std::string& instance_name) {
|
|
/* Deposit invalid values as default */
|
|
std::pair<ModuleId, size_t> instance_info(ModuleId::INVALID(), 0);
|
|
|
|
/* Search all the child module and see we have a match */
|
|
for (const ModuleId& child : module_manager.child_modules(parent)) {
|
|
size_t child_instance =
|
|
module_manager.instance_id(parent, child, instance_name);
|
|
if (true == module_manager.valid_module_instance_id(parent, child,
|
|
child_instance)) {
|
|
instance_info.first = child;
|
|
instance_info.second = child_instance;
|
|
return instance_info;
|
|
}
|
|
}
|
|
|
|
return instance_info;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Add a module to the module manager based on the circuit-level
|
|
* description of a circuit model
|
|
* This function add a module with a given customized name
|
|
* as well as add the ports of circuit model to the module manager
|
|
******************************************************************************/
|
|
ModuleId add_circuit_model_to_module_manager(
|
|
ModuleManager& module_manager, const CircuitLibrary& circuit_lib,
|
|
const CircuitModelId& circuit_model, const std::string& module_name) {
|
|
ModuleId module = module_manager.add_module(module_name);
|
|
VTR_ASSERT(ModuleId::INVALID() != module);
|
|
|
|
/* Identify module usage based on circuit type:
|
|
* LUT, SRAM, CCFF, I/O have specific usages
|
|
* Others will be classified as hard IPs
|
|
*/
|
|
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(circuit_model)) {
|
|
module_manager.set_module_usage(module, ModuleManager::MODULE_LUT);
|
|
} else if (CIRCUIT_MODEL_SRAM == circuit_lib.model_type(circuit_model)) {
|
|
module_manager.set_module_usage(module, ModuleManager::MODULE_CONFIG);
|
|
} else if (CIRCUIT_MODEL_CCFF == circuit_lib.model_type(circuit_model)) {
|
|
module_manager.set_module_usage(module, ModuleManager::MODULE_CONFIG);
|
|
} else if (CIRCUIT_MODEL_IOPAD == circuit_lib.model_type(circuit_model)) {
|
|
module_manager.set_module_usage(module, ModuleManager::MODULE_IO);
|
|
} else if (CIRCUIT_MODEL_WIRE == circuit_lib.model_type(circuit_model)) {
|
|
module_manager.set_module_usage(module, ModuleManager::MODULE_INTERC);
|
|
} else if (CIRCUIT_MODEL_CHAN_WIRE == circuit_lib.model_type(circuit_model)) {
|
|
module_manager.set_module_usage(module, ModuleManager::MODULE_INTERC);
|
|
} else {
|
|
module_manager.set_module_usage(module, ModuleManager::MODULE_HARD_IP);
|
|
}
|
|
|
|
/* Add ports */
|
|
/* Find global ports and add one by one
|
|
* Non-I/O Global input ports will be considered as global port to be shorted
|
|
* wired in the context of module manager I/O Global output ports will be
|
|
* considered as general purpose output port in the context of module manager
|
|
* I/O Global inout ports will be considered as general purpose i/o port in
|
|
* the context of module manager
|
|
*/
|
|
for (const auto& port :
|
|
circuit_lib.model_global_ports(circuit_model, false)) {
|
|
BasicPort port_info(circuit_lib.port_prefix(port),
|
|
circuit_lib.port_size(port));
|
|
ModulePortId module_port = ModulePortId::INVALID();
|
|
|
|
if ((CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(port)) &&
|
|
(false == circuit_lib.port_is_io(port))) {
|
|
module_port = module_manager.add_port(module, port_info,
|
|
ModuleManager::MODULE_GLOBAL_PORT);
|
|
} else if (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(port)) {
|
|
module_port = module_manager.add_port(module, port_info,
|
|
ModuleManager::MODULE_GLOBAL_PORT);
|
|
} else if ((CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(port)) &&
|
|
(true == circuit_lib.port_is_io(port))) {
|
|
module_port = module_manager.add_port(module, port_info,
|
|
ModuleManager::MODULE_GPIN_PORT);
|
|
} else if (CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port)) {
|
|
VTR_ASSERT(true == circuit_lib.port_is_io(port));
|
|
module_port = module_manager.add_port(module, port_info,
|
|
ModuleManager::MODULE_GPOUT_PORT);
|
|
} else if ((CIRCUIT_MODEL_PORT_INOUT == circuit_lib.port_type(port)) &&
|
|
(true == circuit_lib.port_is_io(port))) {
|
|
module_port = module_manager.add_port(module, port_info,
|
|
ModuleManager::MODULE_GPIO_PORT);
|
|
}
|
|
|
|
/* Specify if the port can be mapped to an data signal */
|
|
if (true == module_manager.valid_module_port_id(module, module_port)) {
|
|
if (true == circuit_lib.port_is_data_io(port)) {
|
|
module_manager.set_port_is_mappable_io(module, module_port, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Find other ports and add one by one */
|
|
/* Create a type-to-type map for ports */
|
|
std::map<enum e_circuit_model_port_type, ModuleManager::e_module_port_type>
|
|
port_type2type_map;
|
|
port_type2type_map[CIRCUIT_MODEL_PORT_INOUT] =
|
|
ModuleManager::MODULE_INOUT_PORT;
|
|
port_type2type_map[CIRCUIT_MODEL_PORT_INPUT] =
|
|
ModuleManager::MODULE_INPUT_PORT;
|
|
port_type2type_map[CIRCUIT_MODEL_PORT_CLOCK] =
|
|
ModuleManager::MODULE_INPUT_PORT;
|
|
port_type2type_map[CIRCUIT_MODEL_PORT_SRAM] =
|
|
ModuleManager::MODULE_INPUT_PORT;
|
|
port_type2type_map[CIRCUIT_MODEL_PORT_BL] = ModuleManager::MODULE_INPUT_PORT;
|
|
port_type2type_map[CIRCUIT_MODEL_PORT_BLB] = ModuleManager::MODULE_INPUT_PORT;
|
|
port_type2type_map[CIRCUIT_MODEL_PORT_WL] = ModuleManager::MODULE_INPUT_PORT;
|
|
port_type2type_map[CIRCUIT_MODEL_PORT_WLB] = ModuleManager::MODULE_INPUT_PORT;
|
|
port_type2type_map[CIRCUIT_MODEL_PORT_WLR] = ModuleManager::MODULE_INPUT_PORT;
|
|
port_type2type_map[CIRCUIT_MODEL_PORT_OUTPUT] =
|
|
ModuleManager::MODULE_OUTPUT_PORT;
|
|
|
|
/* Input ports (ignore all the global ports when searching the circuit_lib */
|
|
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);
|
|
}
|
|
}
|
|
|
|
/* Return the new id */
|
|
return module;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Add a module to the module manager based on the circuit-level
|
|
* description of a circuit model
|
|
* This function add a module in the name of the circuit model
|
|
* as well as add the ports of circuit model to the module manager
|
|
*
|
|
* This function is a wrapper of a more customizable function in the same name
|
|
******************************************************************************/
|
|
ModuleId add_circuit_model_to_module_manager(
|
|
ModuleManager& module_manager, const CircuitLibrary& circuit_lib,
|
|
const CircuitModelId& circuit_model) {
|
|
return add_circuit_model_to_module_manager(
|
|
module_manager, circuit_lib, circuit_model,
|
|
circuit_lib.model_name(circuit_model));
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add a list of ports that are used for reserved SRAM ports to a module
|
|
* in the module manager
|
|
* The reserved SRAM ports are mainly designed for RRAM-based FPGA,
|
|
* which are shared across modules.
|
|
* Note that different modules may require different size of reserved
|
|
* SRAM ports but their LSB must all start from 0
|
|
* +---------+
|
|
* reserved_sram_port[0:X] --->| ModuleA |
|
|
* +---------+
|
|
*
|
|
* +---------+
|
|
* reserved_sram_port[0:Y] --->| ModuleB |
|
|
* +---------+
|
|
*
|
|
********************************************************************/
|
|
void add_reserved_sram_ports_to_module_manager(ModuleManager& module_manager,
|
|
const ModuleId& module_id,
|
|
const size_t& port_size) {
|
|
/* Add a reserved BLB port to the module */
|
|
std::string blb_port_name =
|
|
generate_reserved_sram_port_name(CIRCUIT_MODEL_PORT_BLB);
|
|
BasicPort blb_module_port(blb_port_name, port_size);
|
|
/* Add generated ports to the ModuleManager */
|
|
module_manager.add_port(module_id, blb_module_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
|
|
/* Add a reserved BLB port to the module */
|
|
std::string wl_port_name =
|
|
generate_reserved_sram_port_name(CIRCUIT_MODEL_PORT_WL);
|
|
BasicPort wl_module_port(wl_port_name, port_size);
|
|
/* Add generated ports to the ModuleManager */
|
|
module_manager.add_port(module_id, wl_module_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add a list of ports that are used for formal verification to a module
|
|
* in the module manager
|
|
*
|
|
* The formal verification port will appear only when a pre-processing flag is
|
|
*defined This function will add the pre-processing flag along with the port
|
|
********************************************************************/
|
|
void add_formal_verification_sram_ports_to_module_manager(
|
|
ModuleManager& module_manager, const ModuleId& module_id,
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model,
|
|
const std::string& preproc_flag, const size_t& port_size) {
|
|
/* Create a port */
|
|
std::string port_name =
|
|
generate_formal_verification_sram_port_name(circuit_lib, sram_model);
|
|
BasicPort module_port(port_name, port_size);
|
|
/* Add generated ports to the ModuleManager */
|
|
ModulePortId port_id = module_manager.add_port(
|
|
module_id, module_port, ModuleManager::MODULE_INPUT_PORT);
|
|
/* Add pre-processing flag if defined */
|
|
module_manager.set_port_preproc_flag(module_id, port_id, preproc_flag);
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add a list of ports that are used for SRAM configuration to a module
|
|
* in the module manager
|
|
* The type and names of added ports strongly depend on the
|
|
* organization of SRAMs.
|
|
* 1. Standalone SRAMs:
|
|
* two ports will be added, which are BL and WL
|
|
* 2. Scan-chain Flip-flops:
|
|
* two ports will be added, which are the head of scan-chain
|
|
* and the tail of scan-chain
|
|
* IMPORTANT: the port size will be forced to 1 in this case
|
|
* because the head and tail are both 1-bit ports!!!
|
|
* 3. Memory decoders:
|
|
* 2-4 ports will be added, depending on the ports available in the SRAM
|
|
* Among these, two ports are mandatory: BL and WL
|
|
* The other two ports are optional: BLB and WLB
|
|
* Note that the constraints are correletated to the checking rules
|
|
* in check_circuit_library()
|
|
* 4. Frame-based memory:
|
|
* - An Enable signal
|
|
* - An address port, whose size depends on the number of config bits
|
|
* and the maximum size of address ports of configurable children
|
|
* - An data_in port (single-bit)
|
|
********************************************************************/
|
|
void add_sram_ports_to_module_manager(
|
|
ModuleManager& module_manager, const ModuleId& module_id,
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model,
|
|
const e_config_protocol_type sram_orgz_type, const size_t& num_config_bits) {
|
|
std::vector<std::string> sram_port_names =
|
|
generate_sram_port_names(circuit_lib, sram_model, sram_orgz_type);
|
|
size_t sram_port_size =
|
|
generate_sram_port_size(sram_orgz_type, num_config_bits);
|
|
|
|
/* Add ports to the module manager */
|
|
switch (sram_orgz_type) {
|
|
case CONFIG_MEM_FEEDTHROUGH:
|
|
case CONFIG_MEM_STANDALONE:
|
|
case CONFIG_MEM_QL_MEMORY_BANK:
|
|
case CONFIG_MEM_MEMORY_BANK: {
|
|
for (const std::string& sram_port_name : sram_port_names) {
|
|
/* Add generated ports to the ModuleManager */
|
|
BasicPort sram_port(sram_port_name, sram_port_size);
|
|
module_manager.add_port(module_id, sram_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
}
|
|
break;
|
|
}
|
|
case CONFIG_MEM_SCAN_CHAIN: {
|
|
/* Note that configuration chain tail is an output while head is an input
|
|
* IMPORTANT: this is co-designed with function generate_sram_port_names()
|
|
* If the return vector is changed, the following codes MUST be adapted!
|
|
*/
|
|
VTR_ASSERT(2 == sram_port_names.size());
|
|
size_t port_counter = 0;
|
|
for (const std::string& sram_port_name : sram_port_names) {
|
|
/* Add generated ports to the ModuleManager */
|
|
BasicPort sram_port(sram_port_name, sram_port_size);
|
|
if (0 == port_counter) {
|
|
module_manager.add_port(module_id, sram_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
} else {
|
|
VTR_ASSERT(1 == port_counter);
|
|
module_manager.add_port(module_id, sram_port,
|
|
ModuleManager::MODULE_OUTPUT_PORT);
|
|
}
|
|
port_counter++;
|
|
}
|
|
break;
|
|
}
|
|
case CONFIG_MEM_FRAME_BASED: {
|
|
BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1);
|
|
module_manager.add_port(module_id, en_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
|
|
BasicPort addr_port(std::string(DECODER_ADDRESS_PORT_NAME),
|
|
num_config_bits);
|
|
module_manager.add_port(module_id, addr_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
|
|
BasicPort din_port(std::string(DECODER_DATA_IN_PORT_NAME), 1);
|
|
module_manager.add_port(module_id, din_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
|
"Invalid type of SRAM organization !\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* @brief Add a list of ports that are used for SRAM configuration to module
|
|
* in the module manager
|
|
* @note
|
|
* This function is only applicable to programmable blocks, which are
|
|
* - Grid
|
|
* - CBX/CBY
|
|
* - SB
|
|
* @note
|
|
* The major difference between this function and the
|
|
*add_sram_ports_to_module_manager() is the size of sram ports to be added when
|
|
*QL memory bank is selected This function will merge/group BL/WLs by
|
|
*considering a memory bank organization at block-level
|
|
********************************************************************/
|
|
void add_pb_sram_ports_to_module_manager(
|
|
ModuleManager& module_manager, const ModuleId& module_id,
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model,
|
|
const e_config_protocol_type sram_orgz_type, const size_t& num_config_bits,
|
|
const uint32_t defined_num_wl) {
|
|
if (defined_num_wl) {
|
|
// Only support defined_num_wl if the configuration mode is QL Memory Bank
|
|
VTR_ASSERT(sram_orgz_type == CONFIG_MEM_QL_MEMORY_BANK);
|
|
}
|
|
std::vector<std::string> sram_port_names =
|
|
generate_sram_port_names(circuit_lib, sram_model, sram_orgz_type);
|
|
size_t sram_port_size =
|
|
generate_pb_sram_port_size(sram_orgz_type, num_config_bits, defined_num_wl);
|
|
|
|
/* Add ports to the module manager */
|
|
switch (sram_orgz_type) {
|
|
case CONFIG_MEM_QL_MEMORY_BANK:
|
|
for (const std::string& sram_port_name : sram_port_names) {
|
|
/* Add generated ports to the ModuleManager */
|
|
BasicPort sram_port(sram_port_name, sram_port_size);
|
|
/* For WL and WLR ports, we need to fine-tune it */
|
|
if ((CIRCUIT_MODEL_PORT_WL ==
|
|
circuit_lib.port_type(
|
|
circuit_lib.model_port(sram_model, sram_port_name))) ||
|
|
(CIRCUIT_MODEL_PORT_WLR ==
|
|
circuit_lib.port_type(
|
|
circuit_lib.model_port(sram_model, sram_port_name)))) {
|
|
sram_port.set_width(
|
|
find_memory_wl_decoder_data_size(num_config_bits, sram_port_size));
|
|
}
|
|
module_manager.add_port(module_id, sram_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
}
|
|
break;
|
|
case CONFIG_MEM_STANDALONE:
|
|
case CONFIG_MEM_MEMORY_BANK: {
|
|
for (const std::string& sram_port_name : sram_port_names) {
|
|
/* Add generated ports to the ModuleManager */
|
|
BasicPort sram_port(sram_port_name, sram_port_size);
|
|
module_manager.add_port(module_id, sram_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
}
|
|
break;
|
|
}
|
|
case CONFIG_MEM_SCAN_CHAIN: {
|
|
/* Note that configuration chain tail is an output while head is an input
|
|
* IMPORTANT: this is co-designed with function generate_sram_port_names()
|
|
* If the return vector is changed, the following codes MUST be adapted!
|
|
*/
|
|
VTR_ASSERT(2 == sram_port_names.size());
|
|
size_t port_counter = 0;
|
|
for (const std::string& sram_port_name : sram_port_names) {
|
|
/* Add generated ports to the ModuleManager */
|
|
BasicPort sram_port(sram_port_name, sram_port_size);
|
|
if (0 == port_counter) {
|
|
module_manager.add_port(module_id, sram_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
} else {
|
|
VTR_ASSERT(1 == port_counter);
|
|
module_manager.add_port(module_id, sram_port,
|
|
ModuleManager::MODULE_OUTPUT_PORT);
|
|
}
|
|
port_counter++;
|
|
}
|
|
break;
|
|
}
|
|
case CONFIG_MEM_FRAME_BASED: {
|
|
BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1);
|
|
module_manager.add_port(module_id, en_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
|
|
BasicPort addr_port(std::string(DECODER_ADDRESS_PORT_NAME),
|
|
num_config_bits);
|
|
module_manager.add_port(module_id, addr_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
|
|
BasicPort din_port(std::string(DECODER_DATA_IN_PORT_NAME), 1);
|
|
module_manager.add_port(module_id, din_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
|
"Invalid type of SRAM organization !\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add ports of a pb_type block to module manager
|
|
* Port addition will follow the sequence: inout, input, output, clock
|
|
* This will help use to keep a clean module definition when printing out
|
|
* To avoid port mismatch between the pb_type and its linked circuit model
|
|
* This function will also check that each pb_type port is actually exist
|
|
* in the linked circuit model
|
|
*******************************************************************/
|
|
void add_primitive_pb_type_ports_to_module_manager(
|
|
ModuleManager& module_manager, const ModuleId& module_id,
|
|
t_pb_type* cur_pb_type, const VprDeviceAnnotation& vpr_device_annotation) {
|
|
/* Find the inout ports required by the primitive pb_type, and add them to the
|
|
* module */
|
|
std::vector<t_port*> pb_type_inout_ports =
|
|
find_pb_type_ports_match_circuit_model_port_type(
|
|
cur_pb_type, CIRCUIT_MODEL_PORT_INOUT, vpr_device_annotation);
|
|
for (auto port : pb_type_inout_ports) {
|
|
BasicPort module_port(generate_pb_type_port_name(port), port->num_pins);
|
|
module_manager.add_port(module_id, module_port,
|
|
ModuleManager::MODULE_INOUT_PORT);
|
|
/* Set the port to be wire-connection */
|
|
module_manager.set_port_is_wire(module_id, module_port.get_name(), true);
|
|
}
|
|
|
|
/* Find the input ports required by the primitive pb_type, and add them to the
|
|
* module */
|
|
std::vector<t_port*> pb_type_input_ports =
|
|
find_pb_type_ports_match_circuit_model_port_type(
|
|
cur_pb_type, CIRCUIT_MODEL_PORT_INPUT, vpr_device_annotation);
|
|
for (auto port : pb_type_input_ports) {
|
|
BasicPort module_port(generate_pb_type_port_name(port), port->num_pins);
|
|
module_manager.add_port(module_id, module_port,
|
|
ModuleManager::MODULE_INPUT_PORT);
|
|
/* Set the port to be wire-connection */
|
|
module_manager.set_port_is_wire(module_id, module_port.get_name(), true);
|
|
}
|
|
|
|
/* Find the output ports required by the primitive pb_type, and add them to
|
|
* the module */
|
|
std::vector<t_port*> pb_type_output_ports =
|
|
find_pb_type_ports_match_circuit_model_port_type(
|
|
cur_pb_type, CIRCUIT_MODEL_PORT_OUTPUT, vpr_device_annotation);
|
|
for (auto port : pb_type_output_ports) {
|
|
BasicPort module_port(generate_pb_type_port_name(port), port->num_pins);
|
|
module_manager.add_port(module_id, module_port,
|
|
ModuleManager::MODULE_OUTPUT_PORT);
|
|
/* Set the port to be wire-connection */
|
|
module_manager.set_port_is_wire(module_id, module_port.get_name(), true);
|
|
}
|
|
|
|
/* Find the clock ports required by the primitive pb_type, and add them to the
|
|
* module */
|
|
std::vector<t_port*> pb_type_clock_ports =
|
|
find_pb_type_ports_match_circuit_model_port_type(
|
|
cur_pb_type, CIRCUIT_MODEL_PORT_CLOCK, vpr_device_annotation);
|
|
for (auto port : pb_type_clock_ports) {
|
|
BasicPort module_port(generate_pb_type_port_name(port), port->num_pins);
|
|
module_manager.add_port(module_id, module_port,
|
|
ModuleManager::MODULE_CLOCK_PORT);
|
|
/* Set the port to be wire-connection */
|
|
module_manager.set_port_is_wire(module_id, module_port.get_name(), true);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add ports of a pb_type block to module manager
|
|
* This function is designed for non-primitive pb_types, which are
|
|
* NOT linked to any circuit model.
|
|
* Actually, this makes things much simpler.
|
|
* We just iterate over all the ports and add it to the module
|
|
* with the naming convention
|
|
*******************************************************************/
|
|
void add_pb_type_ports_to_module_manager(ModuleManager& module_manager,
|
|
const ModuleId& module_id,
|
|
t_pb_type* cur_pb_type) {
|
|
/* Create a type-to-type mapping between module ports and pb_type ports */
|
|
std::map<PORTS, ModuleManager::e_module_port_type> port_type2type_map;
|
|
port_type2type_map[IN_PORT] = ModuleManager::MODULE_INPUT_PORT;
|
|
port_type2type_map[OUT_PORT] = ModuleManager::MODULE_OUTPUT_PORT;
|
|
port_type2type_map[INOUT_PORT] = ModuleManager::MODULE_INOUT_PORT;
|
|
|
|
for (int port = 0; port < cur_pb_type->num_ports; ++port) {
|
|
t_port* pb_type_port = &(cur_pb_type->ports[port]);
|
|
BasicPort module_port(generate_pb_type_port_name(pb_type_port),
|
|
pb_type_port->num_pins);
|
|
module_manager.add_port(module_id, module_port,
|
|
port_type2type_map[pb_type_port->type]);
|
|
/* Set the port to be wire-connection */
|
|
module_manager.set_port_is_wire(module_id, module_port.get_name(), true);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Identify if a net is a local wire inside a module:
|
|
* A net is a local wire if it connects between two instances,
|
|
* It means that any of its source and sink modules should not include current
|
|
*module_id
|
|
*******************************************************************/
|
|
bool module_net_is_local_wire(const ModuleManager& module_manager,
|
|
const ModuleId& module_id,
|
|
const ModuleNetId& module_net) {
|
|
/* Check all the sink modules of the net,
|
|
* if we have a source module is the current module, this is not local wire
|
|
*/
|
|
for (ModuleId src_module :
|
|
module_manager.net_source_modules(module_id, module_net)) {
|
|
if (module_id == src_module) {
|
|
/* Here, this is not a local wire */
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Check all the sink modules of the net */
|
|
for (ModuleId sink_module :
|
|
module_manager.net_sink_modules(module_id, module_net)) {
|
|
if (module_id == sink_module) {
|
|
/* Here, this is not a local wire */
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/********************************************************************
|
|
* Identify if a net is an output short connection inside a module:
|
|
* The short connection is defined as the direct connection
|
|
* between two outputs port of the module
|
|
*
|
|
* module
|
|
* +-----------------------------+
|
|
* |
|
|
* src------>+--------------->|--->outputA
|
|
* | |
|
|
* | |
|
|
* +--------------->|--->outputB
|
|
* +-----------------------------+
|
|
|
|
*******************************************************************/
|
|
bool module_net_include_output_short_connection(
|
|
const ModuleManager& module_manager, const ModuleId& module_id,
|
|
const ModuleNetId& module_net) {
|
|
/* Check all the sink modules of the net */
|
|
size_t contain_num_module_output = 0;
|
|
for (ModuleId sink_module :
|
|
module_manager.net_sink_modules(module_id, module_net)) {
|
|
if (module_id == sink_module) {
|
|
contain_num_module_output++;
|
|
}
|
|
}
|
|
|
|
/* If we have found more than 1 module outputs, it indicated output short
|
|
* connection! */
|
|
return (1 < contain_num_module_output);
|
|
}
|
|
|
|
/********************************************************************
|
|
* Identify if a net is a local short connection inside a module:
|
|
* The short connection is defined as the direct connection
|
|
* between an input port of the module and an output port of the module
|
|
*
|
|
* module
|
|
* +-----------------------------+
|
|
* | |
|
|
* inputA--->|---------------------------->|--->outputB
|
|
* | |
|
|
* | |
|
|
* | |
|
|
* +-----------------------------+
|
|
*******************************************************************/
|
|
bool module_net_include_local_short_connection(
|
|
const ModuleManager& module_manager, const ModuleId& module_id,
|
|
const ModuleNetId& module_net) {
|
|
/* Check all the sink modules of the net,
|
|
* if we have a source module is the current module, this is not local wire
|
|
*/
|
|
bool contain_module_input = false;
|
|
for (ModuleId src_module :
|
|
module_manager.net_source_modules(module_id, module_net)) {
|
|
if (module_id == src_module) {
|
|
contain_module_input = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Check all the sink modules of the net */
|
|
bool contain_module_output = false;
|
|
for (ModuleId sink_module :
|
|
module_manager.net_sink_modules(module_id, module_net)) {
|
|
if (module_id == sink_module) {
|
|
contain_module_output = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return contain_module_input & contain_module_output;
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add the port-to-port connection between a pb_type and its linked circuit
|
|
*model This function is mainly used to create instance of the module for a
|
|
*pb_type
|
|
*
|
|
* Note: this function SHOULD be called after the pb_type_module is created
|
|
* and its child module is created!
|
|
*******************************************************************/
|
|
void add_primitive_pb_type_module_nets(
|
|
ModuleManager& module_manager, const ModuleId& pb_type_module,
|
|
const ModuleId& child_module, const size_t& child_instance_id,
|
|
const CircuitLibrary& circuit_lib, t_pb_type* cur_pb_type,
|
|
const VprDeviceAnnotation& vpr_device_annotation) {
|
|
for (int iport = 0; iport < cur_pb_type->num_ports; ++iport) {
|
|
t_port* pb_type_port = &(cur_pb_type->ports[iport]);
|
|
/* Must have a linked circuit model port */
|
|
VTR_ASSERT(CircuitPortId::INVALID() !=
|
|
vpr_device_annotation.pb_circuit_port(pb_type_port));
|
|
|
|
/* Find the source port in pb_type module */
|
|
/* Get the src module port id */
|
|
ModulePortId src_module_port_id = module_manager.find_module_port(
|
|
pb_type_module, generate_pb_type_port_name(pb_type_port));
|
|
VTR_ASSERT(ModulePortId::INVALID() != src_module_port_id);
|
|
BasicPort src_port =
|
|
module_manager.module_port(pb_type_module, src_module_port_id);
|
|
|
|
/* Get the des module port id */
|
|
std::string des_module_port_name = circuit_lib.port_prefix(
|
|
vpr_device_annotation.pb_circuit_port(pb_type_port));
|
|
ModulePortId des_module_port_id =
|
|
module_manager.find_module_port(child_module, des_module_port_name);
|
|
VTR_ASSERT(ModulePortId::INVALID() != des_module_port_id);
|
|
BasicPort des_port =
|
|
module_manager.module_port(child_module, des_module_port_id);
|
|
|
|
/* Port size must match */
|
|
VTR_ASSERT(src_port.get_width() == des_port.get_width());
|
|
|
|
/* For each pin, generate the nets.
|
|
* For non-output ports (input ports, inout ports and clock ports),
|
|
* src_port is the source of the net
|
|
* For output ports
|
|
* src_port is the sink of the net
|
|
*/
|
|
switch (pb_type_port->type) {
|
|
case IN_PORT:
|
|
case INOUT_PORT:
|
|
for (size_t pin_id = 0; pin_id < src_port.pins().size(); ++pin_id) {
|
|
ModuleNetId net = module_manager.create_module_net(pb_type_module);
|
|
/* Add net source */
|
|
module_manager.add_module_net_source(
|
|
pb_type_module, net, pb_type_module, 0, src_module_port_id,
|
|
src_port.pins()[pin_id]);
|
|
/* Add net sink */
|
|
module_manager.add_module_net_sink(
|
|
pb_type_module, net, child_module, child_instance_id,
|
|
des_module_port_id, des_port.pins()[pin_id]);
|
|
}
|
|
break;
|
|
case OUT_PORT:
|
|
for (size_t pin_id = 0; pin_id < src_port.pins().size(); ++pin_id) {
|
|
ModuleNetId net = module_manager.create_module_net(pb_type_module);
|
|
/* Add net source */
|
|
module_manager.add_module_net_source(
|
|
pb_type_module, net, child_module, child_instance_id,
|
|
des_module_port_id, des_port.pins()[pin_id]);
|
|
/* Add net sink */
|
|
module_manager.add_module_net_sink(
|
|
pb_type_module, net, pb_type_module, 0, src_module_port_id,
|
|
src_port.pins()[pin_id]);
|
|
}
|
|
break;
|
|
default:
|
|
VTR_LOG_ERROR("Invalid port of pb_type!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add the port-to-port connection between a logic module
|
|
* and a memory module
|
|
* Create nets to wire SRAM ports between logic module and memory module
|
|
*
|
|
* The information about SRAM ports of logic module are stored in the
|
|
* mem_output_bus_ports, where element [0] denotes the SRAM port while
|
|
* element [1] denotes the SRAMb port
|
|
*
|
|
* +---------+ +--------+
|
|
* | | regular SRAM port | |
|
|
* | Logic |-----------------------+ | Memory |
|
|
* | Module | mode-select SRAM port |->| Module |
|
|
* | |-----------------------+ | |
|
|
* +---------+ +--------+
|
|
*
|
|
* There could be multiple SRAM ports of logic module, which are wired to
|
|
* the SRAM ports of memory module
|
|
*
|
|
* Note: this function SHOULD be called after the pb_type_module is created
|
|
* and its child module (logic_module and memory_module) is created!
|
|
*
|
|
* Note: this function only handle either SRAM or SRAMb ports.
|
|
* So, this function may be called twice to complete the wiring
|
|
*******************************************************************/
|
|
static void add_module_nets_between_logic_and_memory_sram_ports(
|
|
ModuleManager& module_manager, const ModuleId& parent_module,
|
|
const ModuleId& logic_module, const size_t& logic_instance_id,
|
|
const ModuleId& memory_module, const size_t& memory_instance_id,
|
|
const std::vector<ModulePortId>& logic_module_sram_port_ids,
|
|
const ModulePortId& mem_module_sram_port_id) {
|
|
/* Find mem_output_bus ports in logic module */
|
|
std::vector<BasicPort> logic_module_sram_ports;
|
|
for (const ModulePortId& logic_module_sram_port_id :
|
|
logic_module_sram_port_ids) {
|
|
logic_module_sram_ports.push_back(
|
|
module_manager.module_port(logic_module, logic_module_sram_port_id));
|
|
}
|
|
|
|
/* Create a list of virtual ports to align with the SRAM port of logic module
|
|
* Physical ports:
|
|
*
|
|
* logic_module_sram_port[0] logic_module_sram_port[1]
|
|
*
|
|
* LSB[0]------------>MSB[0] LSB------------------>MSB
|
|
*
|
|
* memory_sram_port
|
|
* LSBY---------------------------------------------->MSBY
|
|
*
|
|
* Virtual ports:
|
|
* mem_module_sram_port[0] mem_module_sram_port[1]
|
|
* LSBY--------------->MSBX MSBX+1------------------>MSBY
|
|
*
|
|
*/
|
|
BasicPort mem_module_port =
|
|
module_manager.module_port(memory_module, mem_module_sram_port_id);
|
|
std::vector<BasicPort> virtual_mem_module_ports;
|
|
|
|
/* Create a counter for the LSB of virtual ports */
|
|
size_t port_lsb = 0;
|
|
for (const BasicPort& logic_module_sram_port : logic_module_sram_ports) {
|
|
BasicPort virtual_port;
|
|
virtual_port.set_name(mem_module_port.get_name());
|
|
virtual_port.set_width(port_lsb,
|
|
port_lsb + logic_module_sram_port.get_width() - 1);
|
|
virtual_mem_module_ports.push_back(virtual_port);
|
|
port_lsb = virtual_port.get_msb() + 1;
|
|
}
|
|
/* port_lsb should be aligned with the MSB of memory_sram_port */
|
|
VTR_ASSERT(port_lsb == mem_module_port.get_msb() + 1);
|
|
|
|
/* Wire port to port */
|
|
for (size_t port_index = 0; port_index < logic_module_sram_ports.size();
|
|
++port_index) {
|
|
/* Create a net for each pin */
|
|
for (size_t pin_id = 0;
|
|
pin_id < logic_module_sram_ports[port_index].pins().size(); ++pin_id) {
|
|
ModuleNetId net = module_manager.create_module_net(parent_module);
|
|
/* TODO: Give a name to make it clear */
|
|
std::string net_name =
|
|
module_manager.module_name(logic_module) + std::string("_") +
|
|
std::to_string(logic_instance_id) + std::string("_") +
|
|
logic_module_sram_ports[port_index].get_name();
|
|
module_manager.set_net_name(parent_module, net, net_name);
|
|
/* Add net source */
|
|
module_manager.add_module_net_source(
|
|
parent_module, net, logic_module, logic_instance_id,
|
|
logic_module_sram_port_ids[port_index],
|
|
logic_module_sram_ports[port_index].pins()[pin_id]);
|
|
/* Add net sink */
|
|
module_manager.add_module_net_sink(
|
|
parent_module, net, memory_module, memory_instance_id,
|
|
mem_module_sram_port_id,
|
|
virtual_mem_module_ports[port_index].pins()[pin_id]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add the port-to-port connection between a logic module
|
|
* and a memory module
|
|
* Create nets to wire SRAM ports between logic module and memory module
|
|
*
|
|
*
|
|
* +---------+ +--------+
|
|
* | | SRAM ports | |
|
|
* | Logic |----------------------->| Memory |
|
|
* | Module | SRAMb ports | Module |
|
|
* | |----------------------->| |
|
|
* +---------+ +--------+
|
|
*
|
|
* Note: this function SHOULD be called after the pb_type_module is created
|
|
* and its child module (logic_module and memory_module) is created!
|
|
*
|
|
*******************************************************************/
|
|
void add_module_nets_between_logic_and_memory_sram_bus(
|
|
ModuleManager& module_manager, const ModuleId& parent_module,
|
|
const ModuleId& logic_module, const size_t& logic_instance_id,
|
|
const ModuleId& memory_module, const size_t& memory_instance_id,
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& logic_model) {
|
|
/* Connect SRAM port */
|
|
/* Find SRAM ports in the circuit model for logic module */
|
|
std::vector<std::string> logic_model_sram_port_names;
|
|
/* Regular sram port goes first */
|
|
for (CircuitPortId regular_sram_port :
|
|
find_circuit_regular_sram_ports(circuit_lib, logic_model)) {
|
|
logic_model_sram_port_names.push_back(
|
|
circuit_lib.port_prefix(regular_sram_port));
|
|
}
|
|
/* Mode-select sram port goes first */
|
|
for (CircuitPortId mode_select_sram_port :
|
|
find_circuit_mode_select_sram_ports(circuit_lib, logic_model)) {
|
|
logic_model_sram_port_names.push_back(
|
|
circuit_lib.port_prefix(mode_select_sram_port));
|
|
}
|
|
/* Find the port ids in the memory */
|
|
std::vector<ModulePortId> logic_module_sram_port_ids;
|
|
for (const std::string& logic_model_sram_port_name :
|
|
logic_model_sram_port_names) {
|
|
/* Skip non-exist ports */
|
|
if (ModulePortId::INVALID() ==
|
|
module_manager.find_module_port(logic_module,
|
|
logic_model_sram_port_name)) {
|
|
continue;
|
|
}
|
|
logic_module_sram_port_ids.push_back(module_manager.find_module_port(
|
|
logic_module, logic_model_sram_port_name));
|
|
}
|
|
|
|
/* Get the SRAM port name of memory model */
|
|
/* This should be a constant expression and it should be the same for all the
|
|
* memory module! */
|
|
std::string memory_model_sram_port_name =
|
|
generate_configurable_memory_data_out_name();
|
|
/* Find the corresponding ports in memory module */
|
|
ModulePortId mem_module_sram_port_id =
|
|
module_manager.find_module_port(memory_module, memory_model_sram_port_name);
|
|
|
|
/* Do wiring only when we have sram ports */
|
|
if ((false == logic_module_sram_port_ids.empty()) ||
|
|
(ModulePortId::INVALID() == mem_module_sram_port_id)) {
|
|
add_module_nets_between_logic_and_memory_sram_ports(
|
|
module_manager, parent_module, logic_module, logic_instance_id,
|
|
memory_module, memory_instance_id, logic_module_sram_port_ids,
|
|
mem_module_sram_port_id);
|
|
}
|
|
|
|
/* Connect SRAMb port */
|
|
/* Find SRAM ports in the circuit model for logic module */
|
|
std::vector<std::string> logic_model_sramb_port_names;
|
|
/* Regular sram port goes first */
|
|
for (CircuitPortId regular_sram_port :
|
|
find_circuit_regular_sram_ports(circuit_lib, logic_model)) {
|
|
logic_model_sramb_port_names.push_back(
|
|
circuit_lib.port_prefix(regular_sram_port) +
|
|
std::string(INV_PORT_POSTFIX));
|
|
}
|
|
/* Mode-select sram port goes first */
|
|
for (CircuitPortId mode_select_sram_port :
|
|
find_circuit_mode_select_sram_ports(circuit_lib, logic_model)) {
|
|
logic_model_sramb_port_names.push_back(
|
|
circuit_lib.port_prefix(mode_select_sram_port) +
|
|
std::string(INV_PORT_POSTFIX));
|
|
}
|
|
/* Find the port ids in the memory */
|
|
std::vector<ModulePortId> logic_module_sramb_port_ids;
|
|
for (const std::string& logic_model_sramb_port_name :
|
|
logic_model_sramb_port_names) {
|
|
/* Skip non-exist ports */
|
|
if (ModulePortId::INVALID() ==
|
|
module_manager.find_module_port(logic_module,
|
|
logic_model_sramb_port_name)) {
|
|
continue;
|
|
}
|
|
logic_module_sramb_port_ids.push_back(module_manager.find_module_port(
|
|
logic_module, logic_model_sramb_port_name));
|
|
}
|
|
|
|
/* Get the SRAM port name of memory model */
|
|
std::string memory_model_sramb_port_name =
|
|
generate_configurable_memory_inverted_data_out_name();
|
|
/* Find the corresponding ports in memory module */
|
|
ModulePortId mem_module_sramb_port_id = module_manager.find_module_port(
|
|
memory_module, memory_model_sramb_port_name);
|
|
|
|
/* Do wiring only when we have sramb ports */
|
|
if ((false == logic_module_sramb_port_ids.empty()) &&
|
|
(ModulePortId::INVALID() != mem_module_sramb_port_id)) {
|
|
add_module_nets_between_logic_and_memory_sram_ports(
|
|
module_manager, parent_module, logic_module, logic_instance_id,
|
|
memory_module, memory_instance_id, logic_module_sramb_port_ids,
|
|
mem_module_sramb_port_id);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Connect all the memory modules under the parent module in a flatten way
|
|
*
|
|
* BL
|
|
* |
|
|
* +---------------+--------- ... --------+
|
|
* | | |
|
|
* v v v
|
|
* +--------+ +--------+ +--------+
|
|
* | Memory | | Memory | ... | Memory |
|
|
* | Module | | Module | | Module |
|
|
* | [0] | | [1] | | [N-1] |
|
|
* +--------+ +--------+ +--------+
|
|
* ^ ^ ^
|
|
* | | |
|
|
* +------------+----------------------+
|
|
* |
|
|
* WL/WLR
|
|
*
|
|
* Note:
|
|
* - This function will do the connection for only one type of the port,
|
|
* either BL or WL. So, you should call this function twice to complete
|
|
* the configuration bus connection!!!
|
|
*
|
|
*********************************************************************/
|
|
void add_module_nets_cmos_flatten_memory_config_bus(
|
|
ModuleManager& module_manager, const ModuleId& parent_module,
|
|
const e_config_protocol_type& sram_orgz_type,
|
|
const e_circuit_model_port_type& config_port_type,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
/* A counter for the current pin id for the source port of parent module */
|
|
size_t cur_src_pin_id = 0;
|
|
|
|
/* Find the port name of parent module */
|
|
std::string src_port_name =
|
|
generate_sram_port_name(sram_orgz_type, config_port_type);
|
|
ModuleId net_src_module_id = parent_module;
|
|
size_t net_src_instance_id = 0;
|
|
ModulePortId net_src_port_id =
|
|
module_manager.find_module_port(net_src_module_id, src_port_name);
|
|
|
|
/* We may not be able to find WLR port, return now */
|
|
if (!net_src_port_id) {
|
|
return;
|
|
}
|
|
|
|
/* Get the pin id for source port */
|
|
BasicPort net_src_port =
|
|
module_manager.module_port(net_src_module_id, net_src_port_id);
|
|
|
|
for (size_t mem_index = 0;
|
|
mem_index < module_manager.num_configurable_children(parent_module,
|
|
config_child_type);
|
|
++mem_index) {
|
|
ModuleId net_sink_module_id;
|
|
size_t net_sink_instance_id;
|
|
ModulePortId net_sink_port_id;
|
|
|
|
/* Find the port name of next memory module */
|
|
std::string sink_port_name =
|
|
generate_sram_port_name(sram_orgz_type, config_port_type);
|
|
net_sink_module_id = module_manager.configurable_children(
|
|
parent_module, config_child_type)[mem_index];
|
|
net_sink_instance_id = module_manager.configurable_child_instances(
|
|
parent_module, config_child_type)[mem_index];
|
|
net_sink_port_id =
|
|
module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
|
|
|
/* Get the pin id for sink port */
|
|
BasicPort net_sink_port =
|
|
module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
|
|
|
/* Create a net for each pin */
|
|
for (size_t pin_id = 0; pin_id < net_sink_port.pins().size(); ++pin_id) {
|
|
/* Create a net and add source and sink to it */
|
|
ModuleNetId net = create_module_source_pin_net(
|
|
module_manager, parent_module, net_src_module_id, net_src_instance_id,
|
|
net_src_port_id, net_src_port.pins()[cur_src_pin_id]);
|
|
VTR_ASSERT(ModuleNetId::INVALID() != net);
|
|
|
|
/* Add net sink */
|
|
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id,
|
|
net_sink_instance_id, net_sink_port_id,
|
|
net_sink_port.pins()[pin_id]);
|
|
|
|
/* Move to the next src pin */
|
|
cur_src_pin_id++;
|
|
}
|
|
}
|
|
|
|
/* We should used all the pins of the source port!!! */
|
|
VTR_ASSERT(net_src_port.get_width() == cur_src_pin_id);
|
|
}
|
|
|
|
/********************************************************************
|
|
* @brief Connect all the Bit Lines (BL) of child memory modules under the
|
|
* parent module in a memory bank organization
|
|
*
|
|
* BL<0> BL<1> BL<i>
|
|
* | | |
|
|
* v v v
|
|
* +--------+ +--------+ +--------+
|
|
* | Memory | | Memory | ... | Memory |
|
|
* | Module | | Module | | Module |
|
|
* | [0,0] | | [1,0] | | [i,0] |
|
|
* +--------+ +--------+ +--------+
|
|
* | | |
|
|
* v v v
|
|
* +--------+ +--------+ +--------+
|
|
* | Memory | | Memory | ... | Memory |
|
|
* | Module | | Module | | Module |
|
|
* | [0,1] | | [1,1] | | [i,1] |
|
|
* +--------+ +--------+ +--------+
|
|
*
|
|
*********************************************************************/
|
|
void add_module_nets_cmos_memory_bank_bl_config_bus(
|
|
ModuleManager& module_manager, const ModuleId& parent_module,
|
|
const e_config_protocol_type& sram_orgz_type,
|
|
const e_circuit_model_port_type& config_port_type,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
/* A counter for the current pin id for the source port of parent module */
|
|
size_t cur_src_pin_id = 0;
|
|
|
|
/* Find the port name of parent module */
|
|
std::string src_port_name =
|
|
generate_sram_port_name(sram_orgz_type, config_port_type);
|
|
ModuleId net_src_module_id = parent_module;
|
|
size_t net_src_instance_id = 0;
|
|
ModulePortId net_src_port_id =
|
|
module_manager.find_module_port(net_src_module_id, src_port_name);
|
|
|
|
/* Get the pin id for source port */
|
|
BasicPort net_src_port =
|
|
module_manager.module_port(net_src_module_id, net_src_port_id);
|
|
|
|
for (size_t mem_index = 0;
|
|
mem_index <
|
|
module_manager.configurable_children(parent_module, config_child_type)
|
|
.size();
|
|
++mem_index) {
|
|
/* Find the port name of next memory module */
|
|
std::string sink_port_name =
|
|
generate_sram_port_name(sram_orgz_type, config_port_type);
|
|
ModuleId net_sink_module_id = module_manager.configurable_children(
|
|
parent_module, config_child_type)[mem_index];
|
|
size_t net_sink_instance_id = module_manager.configurable_child_instances(
|
|
parent_module, config_child_type)[mem_index];
|
|
ModulePortId net_sink_port_id =
|
|
module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
|
|
|
/* Get the pin id for sink port */
|
|
BasicPort net_sink_port =
|
|
module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
|
|
|
/* Create a net for each pin */
|
|
for (size_t pin_id = 0; pin_id < net_sink_port.pins().size(); ++pin_id) {
|
|
size_t cur_bl_src_pin_id = cur_src_pin_id % net_src_port.pins().size();
|
|
/* Create a net and add source and sink to it */
|
|
ModuleNetId net = create_module_source_pin_net(
|
|
module_manager, parent_module, net_src_module_id, net_src_instance_id,
|
|
net_src_port_id, net_src_port.pins()[cur_bl_src_pin_id]);
|
|
VTR_ASSERT(ModuleNetId::INVALID() != net);
|
|
|
|
/* Add net sink */
|
|
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id,
|
|
net_sink_instance_id, net_sink_port_id,
|
|
net_sink_port.pins()[pin_id]);
|
|
|
|
/* Move to the next src pin */
|
|
cur_src_pin_id++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* @brief Connect all the Word Lines (WL) of child memory modules under the
|
|
* parent module in a memory bank organization
|
|
*
|
|
* +--------+ +--------+ +--------+
|
|
* | Memory | | Memory | ... | Memory |
|
|
* | Module | | Module | | Module |
|
|
* | [0,0] | | [1,0] | | [i,0] |
|
|
* +--------+ +--------+ +--------+
|
|
* ^ ^ ^
|
|
* | | |
|
|
* +------------+----------------------+
|
|
* |
|
|
* WL<0>/WLR<0>
|
|
*
|
|
* +--------+ +--------+ +--------+
|
|
* | Memory | | Memory | ... | Memory |
|
|
* | Module | | Module | | Module |
|
|
* | [0,1] | | [1,1] | | [i,1] |
|
|
* +--------+ +--------+ +--------+
|
|
* ^ ^ ^
|
|
* | | |
|
|
* +------------+----------------------+
|
|
* |
|
|
* WL<1>/WLR<1>
|
|
*
|
|
*********************************************************************/
|
|
void add_module_nets_cmos_memory_bank_wl_config_bus(
|
|
ModuleManager& module_manager, const ModuleId& parent_module,
|
|
const e_config_protocol_type& sram_orgz_type,
|
|
const e_circuit_model_port_type& config_port_type,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
/* A counter for the current pin id for the source port of parent module */
|
|
size_t cur_src_pin_id = 0;
|
|
|
|
/* Find the port name of parent module */
|
|
std::string src_port_name =
|
|
generate_sram_port_name(sram_orgz_type, config_port_type);
|
|
std::string bl_port_name =
|
|
generate_sram_port_name(sram_orgz_type, CIRCUIT_MODEL_PORT_BL);
|
|
|
|
ModuleId net_src_module_id = parent_module;
|
|
size_t net_src_instance_id = 0;
|
|
ModulePortId net_src_port_id =
|
|
module_manager.find_module_port(net_src_module_id, src_port_name);
|
|
ModulePortId net_bl_port_id =
|
|
module_manager.find_module_port(net_src_module_id, bl_port_name);
|
|
|
|
/* We may not be able to find WLR port, return now */
|
|
if (!net_src_port_id) {
|
|
return;
|
|
}
|
|
|
|
/* Get the pin id for source port */
|
|
BasicPort net_src_port =
|
|
module_manager.module_port(net_src_module_id, net_src_port_id);
|
|
BasicPort net_bl_port =
|
|
module_manager.module_port(net_src_module_id, net_bl_port_id);
|
|
|
|
for (size_t mem_index = 0;
|
|
mem_index <
|
|
module_manager.configurable_children(parent_module, config_child_type)
|
|
.size();
|
|
++mem_index) {
|
|
/* Find the port name of next memory module */
|
|
std::string sink_port_name =
|
|
generate_sram_port_name(sram_orgz_type, config_port_type);
|
|
ModuleId net_sink_module_id = module_manager.configurable_children(
|
|
parent_module, config_child_type)[mem_index];
|
|
size_t net_sink_instance_id = module_manager.configurable_child_instances(
|
|
parent_module, config_child_type)[mem_index];
|
|
ModulePortId net_sink_port_id =
|
|
module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
|
|
|
/* Get the pin id for sink port */
|
|
BasicPort net_sink_port =
|
|
module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
|
|
|
/* Create a net for each pin */
|
|
for (size_t pin_id = 0; pin_id < net_sink_port.pins().size(); ++pin_id) {
|
|
size_t cur_wl_src_pin_id =
|
|
std::floor(cur_src_pin_id / net_bl_port.pins().size());
|
|
/* Create a net and add source and sink to it */
|
|
ModuleNetId net = create_module_source_pin_net(
|
|
module_manager, parent_module, net_src_module_id, net_src_instance_id,
|
|
net_src_port_id, net_src_port.pins()[cur_wl_src_pin_id]);
|
|
VTR_ASSERT(ModuleNetId::INVALID() != net);
|
|
|
|
/* Add net sink */
|
|
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id,
|
|
net_sink_instance_id, net_sink_port_id,
|
|
net_sink_port.pins()[pin_id]);
|
|
|
|
/* Move to the next src pin */
|
|
cur_src_pin_id++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Connect all the memory modules under the parent module in a chain
|
|
*
|
|
* +--------+ +--------+ +--------+
|
|
* ccff_head --->| Memory |--->| Memory |--->... --->| Memory |----> ccff_tail
|
|
* | Module | | Module | | Module |
|
|
* | [0] | | [1] | | [N-1] |
|
|
* +--------+ +--------+ +--------+
|
|
* For the 1st memory module:
|
|
* net source is the configuration chain head of the primitive module
|
|
* net sink is the configuration chain head of the next memory module
|
|
*
|
|
* For the rest of memory modules:
|
|
* net source is the configuration chain tail of the previous memory module
|
|
* net sink is the configuration chain head of the next memory module
|
|
*********************************************************************/
|
|
void add_module_nets_cmos_memory_chain_config_bus(
|
|
ModuleManager& module_manager, const ModuleId& parent_module,
|
|
const e_config_protocol_type& sram_orgz_type,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
for (size_t mem_index = 0;
|
|
mem_index < module_manager.num_configurable_children(parent_module,
|
|
config_child_type);
|
|
++mem_index) {
|
|
ModuleId net_src_module_id;
|
|
size_t net_src_instance_id;
|
|
ModulePortId net_src_port_id;
|
|
|
|
ModuleId net_sink_module_id;
|
|
size_t net_sink_instance_id;
|
|
ModulePortId net_sink_port_id;
|
|
|
|
if (0 == mem_index) {
|
|
/* Find the port name of configuration chain head */
|
|
std::string src_port_name =
|
|
generate_sram_port_name(sram_orgz_type, CIRCUIT_MODEL_PORT_INPUT);
|
|
net_src_module_id = parent_module;
|
|
net_src_instance_id = 0;
|
|
net_src_port_id =
|
|
module_manager.find_module_port(net_src_module_id, src_port_name);
|
|
|
|
/* Find the port name of next memory module */
|
|
std::string sink_port_name = generate_configuration_chain_head_name();
|
|
net_sink_module_id = module_manager.configurable_children(
|
|
parent_module, config_child_type)[mem_index];
|
|
net_sink_instance_id = module_manager.configurable_child_instances(
|
|
parent_module, config_child_type)[mem_index];
|
|
net_sink_port_id =
|
|
module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
|
} else {
|
|
/* Find the port name of previous memory module */
|
|
std::string src_port_name = generate_configuration_chain_tail_name();
|
|
net_src_module_id = module_manager.configurable_children(
|
|
parent_module, config_child_type)[mem_index - 1];
|
|
net_src_instance_id = module_manager.configurable_child_instances(
|
|
parent_module, config_child_type)[mem_index - 1];
|
|
net_src_port_id =
|
|
module_manager.find_module_port(net_src_module_id, src_port_name);
|
|
|
|
/* Find the port name of next memory module */
|
|
std::string sink_port_name = generate_configuration_chain_head_name();
|
|
net_sink_module_id = module_manager.configurable_children(
|
|
parent_module, config_child_type)[mem_index];
|
|
net_sink_instance_id = module_manager.configurable_child_instances(
|
|
parent_module, config_child_type)[mem_index];
|
|
net_sink_port_id =
|
|
module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
|
}
|
|
|
|
/* Get the pin id for source port */
|
|
BasicPort net_src_port =
|
|
module_manager.module_port(net_src_module_id, net_src_port_id);
|
|
/* Get the pin id for sink port */
|
|
BasicPort net_sink_port =
|
|
module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
|
/* Port sizes of source and sink should match */
|
|
VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
|
|
|
|
/* Create a net for each pin */
|
|
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
|
|
/* Create a net and add source and sink to it */
|
|
ModuleNetId net = create_module_source_pin_net(
|
|
module_manager, parent_module, net_src_module_id, net_src_instance_id,
|
|
net_src_port_id, net_src_port.pins()[pin_id]);
|
|
/* Add net sink */
|
|
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id,
|
|
net_sink_instance_id, net_sink_port_id,
|
|
net_sink_port.pins()[pin_id]);
|
|
}
|
|
}
|
|
|
|
/* For the last memory module:
|
|
* net source is the configuration chain tail of the previous memory module
|
|
* net sink is the configuration chain tail of the primitive module
|
|
*/
|
|
/* Find the port name of previous memory module */
|
|
std::string src_port_name = generate_configuration_chain_tail_name();
|
|
ModuleId net_src_module_id =
|
|
module_manager.configurable_children(parent_module, config_child_type)
|
|
.back();
|
|
size_t net_src_instance_id =
|
|
module_manager
|
|
.configurable_child_instances(parent_module, config_child_type)
|
|
.back();
|
|
ModulePortId net_src_port_id =
|
|
module_manager.find_module_port(net_src_module_id, src_port_name);
|
|
|
|
/* Find the port name of next memory module */
|
|
std::string sink_port_name =
|
|
generate_sram_port_name(sram_orgz_type, CIRCUIT_MODEL_PORT_OUTPUT);
|
|
ModuleId net_sink_module_id = parent_module;
|
|
size_t net_sink_instance_id = 0;
|
|
ModulePortId net_sink_port_id =
|
|
module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
|
|
|
/* Get the pin id for source port */
|
|
BasicPort net_src_port =
|
|
module_manager.module_port(net_src_module_id, net_src_port_id);
|
|
/* Get the pin id for sink port */
|
|
BasicPort net_sink_port =
|
|
module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
|
/* Port sizes of source and sink should match */
|
|
VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
|
|
|
|
/* Create a net for each pin */
|
|
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
|
|
/* Create a net and add source and sink to it */
|
|
ModuleNetId net = create_module_source_pin_net(
|
|
module_manager, parent_module, net_src_module_id, net_src_instance_id,
|
|
net_src_port_id, net_src_port.pins()[pin_id]);
|
|
/* Add net sink */
|
|
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id,
|
|
net_sink_instance_id, net_sink_port_id,
|
|
net_sink_port.pins()[pin_id]);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* This function will create nets for the following types of connections:
|
|
* - Connect the enable signal to the EN of memory module
|
|
* - Connect the address port to the address port of memory module
|
|
* - Connect the data_in (Din) to the data_in of the memory module
|
|
*
|
|
* EN ADDR DATA_IN
|
|
* | | |
|
|
* v v v
|
|
* +-----------------------------+
|
|
* | Memory Module |
|
|
* | [0] |
|
|
* | |
|
|
* +-----------------------------+
|
|
*
|
|
* Note:
|
|
* - This function is ONLY applicable to single configurable child case!!!
|
|
*
|
|
*********************************************************************/
|
|
static void add_module_nets_cmos_memory_frame_short_config_bus(
|
|
ModuleManager& module_manager, const ModuleId& parent_module,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
std::vector<ModuleId> configurable_children =
|
|
module_manager.configurable_children(parent_module, config_child_type);
|
|
|
|
VTR_ASSERT(1 == configurable_children.size());
|
|
ModuleId child_module = configurable_children[0];
|
|
|
|
/* Connect the enable (EN) port of the parent module
|
|
* to the EN port of memory module
|
|
*/
|
|
ModulePortId parent_en_port = module_manager.find_module_port(
|
|
parent_module, std::string(DECODER_ENABLE_PORT_NAME));
|
|
ModulePortId child_en_port = module_manager.find_module_port(
|
|
child_module, std::string(DECODER_ENABLE_PORT_NAME));
|
|
add_module_bus_nets(module_manager, parent_module, parent_module, 0,
|
|
parent_en_port, child_module, 0, child_en_port);
|
|
|
|
/* Connect the address port of the parent module to the child module address
|
|
* port */
|
|
ModulePortId parent_addr_port = module_manager.find_module_port(
|
|
parent_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
|
ModulePortId child_addr_port = module_manager.find_module_port(
|
|
child_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
|
add_module_bus_nets(module_manager, parent_module, parent_module, 0,
|
|
parent_addr_port, child_module, 0, child_addr_port);
|
|
|
|
/* Connect the data_in (Din) of parent module to the data_in of the memory
|
|
* module
|
|
*/
|
|
ModulePortId parent_din_port = module_manager.find_module_port(
|
|
parent_module, std::string(DECODER_DATA_IN_PORT_NAME));
|
|
ModulePortId child_din_port = module_manager.find_module_port(
|
|
child_module, std::string(DECODER_DATA_IN_PORT_NAME));
|
|
add_module_bus_nets(module_manager, parent_module, parent_module, 0,
|
|
parent_din_port, child_module, 0, child_din_port);
|
|
}
|
|
|
|
/********************************************************************
|
|
* This function will
|
|
* - Add a frame decoder to the parent module
|
|
* - If the decoder exists in the library, we use the module
|
|
* - If the decoder does not exist, we create a new module and use it
|
|
* - create nets for the following types of connections:
|
|
* - Connect the EN signal, first few bits of address of parent module
|
|
* to the frame decoder inputs
|
|
* - Connect the enable (EN) port of memory modules under the parent module
|
|
* to the frame decoder outputs
|
|
* - Connect the data_in (Din) of parent module to the data_in of the all
|
|
* the memory modules
|
|
*
|
|
* EN ADDR[X - 1: X - log(N)/log2]
|
|
* | |
|
|
* v v
|
|
* +--------------------------------------------+
|
|
* | Frame-based decoder |
|
|
* | |
|
|
* | Data out |
|
|
* +--------------------------------------------+
|
|
* |
|
|
* +-------------+--------------------+
|
|
* | | |
|
|
* Din | Din | Din |
|
|
* | | | | | |
|
|
* v v v v v v
|
|
* +--------+ +--------+ +--------+
|
|
* | Memory | | Memory | ... | Memory |
|
|
* | Module | | Module | | Module |
|
|
* | [0] | | [1] | | [N-1] |
|
|
* +--------+ +--------+ +--------+
|
|
* ^ ^ ^
|
|
* | | |
|
|
* +-------------+--------------------+
|
|
* |
|
|
* ADDR[X - log(N)/log2 - 1: 0]
|
|
*
|
|
* Note:
|
|
* - X is the port size of address port of the parent module
|
|
* - the address port of child memory modules may be smaller than
|
|
* X - log(N)/log2. In such case, we will drop the MSBs until it fit
|
|
* - This function is only applicable to 2+ configurable children!!!
|
|
*
|
|
*********************************************************************/
|
|
static void add_module_nets_cmos_memory_frame_decoder_config_bus(
|
|
ModuleManager& module_manager, DecoderLibrary& decoder_lib,
|
|
const ModuleId& parent_module,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
std::vector<ModuleId> configurable_children =
|
|
module_manager.configurable_children(parent_module, config_child_type);
|
|
|
|
/* Find the decoder specification */
|
|
size_t addr_size =
|
|
find_mux_local_decoder_addr_size(configurable_children.size());
|
|
/* Data input should match the WL (data_in) of a SRAM */
|
|
size_t data_size = configurable_children.size();
|
|
|
|
/* Search the decoder library and try to find one
|
|
* If not found, create a new module and add it to the module manager
|
|
*/
|
|
DecoderId decoder_id =
|
|
decoder_lib.find_decoder(addr_size, data_size, true, false, false, false);
|
|
if (DecoderId::INVALID() == decoder_id) {
|
|
decoder_id =
|
|
decoder_lib.add_decoder(addr_size, data_size, true, false, false, false);
|
|
}
|
|
VTR_ASSERT(DecoderId::INVALID() != decoder_id);
|
|
|
|
/* Create a module if not existed yet */
|
|
std::string decoder_module_name =
|
|
generate_memory_decoder_subckt_name(addr_size, data_size);
|
|
ModuleId decoder_module = module_manager.find_module(decoder_module_name);
|
|
if (ModuleId::INVALID() == decoder_module) {
|
|
decoder_module = build_frame_memory_decoder_module(module_manager,
|
|
decoder_lib, decoder_id);
|
|
}
|
|
VTR_ASSERT(ModuleId::INVALID() != decoder_module);
|
|
|
|
/* Instanciate the decoder module here */
|
|
VTR_ASSERT(0 == module_manager.num_instance(parent_module, decoder_module));
|
|
module_manager.add_child_module(parent_module, decoder_module, false);
|
|
|
|
/* Connect the enable (EN) port of memory modules under the parent module
|
|
* to the frame decoder inputs
|
|
*/
|
|
ModulePortId parent_en_port = module_manager.find_module_port(
|
|
parent_module, std::string(DECODER_ENABLE_PORT_NAME));
|
|
ModulePortId decoder_en_port = module_manager.find_module_port(
|
|
decoder_module, std::string(DECODER_ENABLE_PORT_NAME));
|
|
add_module_bus_nets(module_manager, parent_module, parent_module, 0,
|
|
parent_en_port, decoder_module, 0, decoder_en_port);
|
|
|
|
/* Connect the address port of the parent module to the frame decoder address
|
|
* port Note that we only connect to the first few bits of address port
|
|
*/
|
|
ModulePortId parent_addr_port = module_manager.find_module_port(
|
|
parent_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
|
ModulePortId decoder_addr_port = module_manager.find_module_port(
|
|
decoder_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
|
BasicPort parent_addr_port_info =
|
|
module_manager.module_port(parent_module, parent_addr_port);
|
|
BasicPort decoder_addr_port_info =
|
|
module_manager.module_port(decoder_module, decoder_addr_port);
|
|
for (size_t ipin = 0; ipin < decoder_addr_port_info.get_width(); ++ipin) {
|
|
ModuleNetId net = module_manager.module_instance_port_net(
|
|
parent_module, parent_module, 0, parent_addr_port,
|
|
parent_addr_port_info.get_msb() - ipin);
|
|
if (ModuleNetId::INVALID() == net) {
|
|
net = module_manager.create_module_net(parent_module);
|
|
/* Configure the net source */
|
|
module_manager.add_module_net_source(
|
|
parent_module, net, parent_module, 0, parent_addr_port,
|
|
parent_addr_port_info.get_msb() - ipin);
|
|
}
|
|
/* Configure the net sink */
|
|
module_manager.add_module_net_sink(parent_module, net, decoder_module, 0,
|
|
decoder_addr_port,
|
|
decoder_addr_port_info.get_msb() - ipin);
|
|
}
|
|
|
|
/* Connect the address port of the parent module to the address port of
|
|
* configurable children Note that we only connect to the last few bits of
|
|
* address port
|
|
*/
|
|
for (size_t mem_index = 0; mem_index < configurable_children.size();
|
|
++mem_index) {
|
|
ModuleId child_module = configurable_children[mem_index];
|
|
size_t child_instance = module_manager.configurable_child_instances(
|
|
parent_module, config_child_type)[mem_index];
|
|
ModulePortId child_addr_port = module_manager.find_module_port(
|
|
child_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
|
BasicPort child_addr_port_info =
|
|
module_manager.module_port(child_module, child_addr_port);
|
|
for (size_t ipin = 0; ipin < child_addr_port_info.get_width(); ++ipin) {
|
|
ModuleNetId net = module_manager.module_instance_port_net(
|
|
parent_module, parent_module, 0, parent_addr_port,
|
|
parent_addr_port_info.get_lsb() + ipin);
|
|
if (ModuleNetId::INVALID() == net) {
|
|
net = module_manager.create_module_net(parent_module);
|
|
/* Configure the net source */
|
|
module_manager.add_module_net_source(
|
|
parent_module, net, parent_module, 0, parent_addr_port,
|
|
parent_addr_port_info.get_lsb() + ipin);
|
|
}
|
|
/* Configure the net sink */
|
|
module_manager.add_module_net_sink(parent_module, net, child_module,
|
|
child_instance, child_addr_port,
|
|
child_addr_port_info.get_lsb() + ipin);
|
|
}
|
|
}
|
|
|
|
/* Connect the data_in (Din) of parent module to the data_in of the all
|
|
* the memory modules
|
|
*/
|
|
ModulePortId parent_din_port = module_manager.find_module_port(
|
|
parent_module, std::string(DECODER_DATA_IN_PORT_NAME));
|
|
for (size_t mem_index = 0; mem_index < configurable_children.size();
|
|
++mem_index) {
|
|
ModuleId child_module = configurable_children[mem_index];
|
|
size_t child_instance = module_manager.configurable_child_instances(
|
|
parent_module, config_child_type)[mem_index];
|
|
ModulePortId child_din_port = module_manager.find_module_port(
|
|
child_module, std::string(DECODER_DATA_IN_PORT_NAME));
|
|
add_module_bus_nets(module_manager, parent_module, parent_module, 0,
|
|
parent_din_port, child_module, child_instance,
|
|
child_din_port);
|
|
}
|
|
|
|
/* Connect the data_out port of the decoder module
|
|
* to the enable port of configurable children
|
|
*/
|
|
ModulePortId decoder_dout_port = module_manager.find_module_port(
|
|
decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME));
|
|
BasicPort decoder_dout_port_info =
|
|
module_manager.module_port(decoder_module, decoder_dout_port);
|
|
VTR_ASSERT(decoder_dout_port_info.get_width() ==
|
|
configurable_children.size());
|
|
for (size_t mem_index = 0; mem_index < configurable_children.size();
|
|
++mem_index) {
|
|
ModuleId child_module = configurable_children[mem_index];
|
|
size_t child_instance = module_manager.configurable_child_instances(
|
|
parent_module, config_child_type)[mem_index];
|
|
ModulePortId child_en_port = module_manager.find_module_port(
|
|
child_module, std::string(DECODER_ENABLE_PORT_NAME));
|
|
BasicPort child_en_port_info =
|
|
module_manager.module_port(child_module, child_en_port);
|
|
for (size_t ipin = 0; ipin < child_en_port_info.get_width(); ++ipin) {
|
|
ModuleNetId net = module_manager.module_instance_port_net(
|
|
parent_module, decoder_module, 0, decoder_dout_port,
|
|
decoder_dout_port_info.pins()[mem_index]);
|
|
if (ModuleNetId::INVALID() == net) {
|
|
net = module_manager.create_module_net(parent_module);
|
|
/* Configure the net source */
|
|
module_manager.add_module_net_source(
|
|
parent_module, net, decoder_module, 0, decoder_dout_port,
|
|
decoder_dout_port_info.pins()[mem_index]);
|
|
}
|
|
/* Configure the net sink */
|
|
module_manager.add_module_net_sink(parent_module, net, child_module,
|
|
child_instance, child_en_port,
|
|
child_en_port_info.pins()[ipin]);
|
|
}
|
|
}
|
|
|
|
/* Add the decoder as the last configurable children */
|
|
module_manager.add_configurable_child(
|
|
parent_module, decoder_module, 0,
|
|
ModuleManager::e_config_child_type::UNIFIED);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Top-level function to add nets for frame-based memories
|
|
* Add nets depending on the need
|
|
* - If there is no configurable child, return directly.
|
|
* - If there is only one configurable child, short wire the EN, ADDR and
|
|
*DATA_IN to it
|
|
* - If there are more than two configurable childern, add a decoder and build
|
|
*interconnection between it and the children
|
|
**********************************************************************/
|
|
void add_module_nets_cmos_memory_frame_config_bus(
|
|
ModuleManager& module_manager, DecoderLibrary& decoder_lib,
|
|
const ModuleId& parent_module,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
if (0 == module_manager.num_configurable_children(parent_module,
|
|
config_child_type)) {
|
|
return;
|
|
}
|
|
|
|
if (1 == module_manager.num_configurable_children(parent_module,
|
|
config_child_type)) {
|
|
add_module_nets_cmos_memory_frame_short_config_bus(
|
|
module_manager, parent_module, config_child_type);
|
|
} else {
|
|
VTR_ASSERT(1 < module_manager.num_configurable_children(parent_module,
|
|
config_child_type));
|
|
add_module_nets_cmos_memory_frame_decoder_config_bus(
|
|
module_manager, decoder_lib, parent_module, config_child_type);
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Add the port-to-port connection between all the memory modules
|
|
* and their parent module
|
|
*
|
|
* Create nets to wire the control signals of memory module to
|
|
* the configuration ports of primitive module
|
|
*
|
|
* Configuration Chain
|
|
* -------------------
|
|
*
|
|
* config_bus (head) config_bus (tail)
|
|
* | ^
|
|
* primitive | |
|
|
* +---------------------------------------------+
|
|
* | | | |
|
|
* | v | |
|
|
* | +-------------------------------------+ |
|
|
* | | CMOS-based Memory Modules | |
|
|
* | +-------------------------------------+ |
|
|
* | | | |
|
|
* | v v |
|
|
* | sram_out sram_outb |
|
|
* | |
|
|
* +---------------------------------------------+
|
|
*
|
|
* Memory bank
|
|
* -----------
|
|
*
|
|
* config_bus (BL) config_bus (WL)
|
|
* | |
|
|
* primitive | |
|
|
* +---------------------------------------------+
|
|
* | | | |
|
|
* | v v |
|
|
* | +-------------------------------------+ |
|
|
* | | CMOS-based Memory Modules | |
|
|
* | +-------------------------------------+ |
|
|
* | | | |
|
|
* | v v |
|
|
* | sram_out sram_outb |
|
|
* | |
|
|
* +---------------------------------------------+
|
|
*
|
|
**********************************************************************/
|
|
static void add_module_nets_cmos_memory_config_bus(
|
|
ModuleManager& module_manager, DecoderLibrary& decoder_lib,
|
|
const ModuleId& parent_module, const e_config_protocol_type& sram_orgz_type,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
switch (sram_orgz_type) {
|
|
case CONFIG_MEM_SCAN_CHAIN: {
|
|
add_module_nets_cmos_memory_chain_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, config_child_type);
|
|
break;
|
|
}
|
|
case CONFIG_MEM_FEEDTHROUGH:
|
|
add_module_nets_cmos_flatten_memory_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_BL,
|
|
config_child_type);
|
|
add_module_nets_cmos_flatten_memory_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_BLB,
|
|
config_child_type);
|
|
break;
|
|
case CONFIG_MEM_STANDALONE:
|
|
case CONFIG_MEM_QL_MEMORY_BANK:
|
|
case CONFIG_MEM_MEMORY_BANK:
|
|
add_module_nets_cmos_flatten_memory_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_BL,
|
|
config_child_type);
|
|
add_module_nets_cmos_flatten_memory_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WL,
|
|
config_child_type);
|
|
add_module_nets_cmos_flatten_memory_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WLR,
|
|
config_child_type);
|
|
break;
|
|
case CONFIG_MEM_FRAME_BASED:
|
|
add_module_nets_cmos_memory_frame_config_bus(
|
|
module_manager, decoder_lib, parent_module, config_child_type);
|
|
break;
|
|
default:
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
|
"Invalid type of SRAM organization!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @brief Add the port-to-port connection between all the memory modules
|
|
* and their parent module. This function creates nets to wire the control
|
|
* signals of memory module to the configuration ports of primitive module
|
|
*
|
|
* @note This function is only applicable to programmable blocks, which are
|
|
* grid, CBX/CBY, SB. Different from the
|
|
add_pb_module_nets_cmos_memory_config_bus(),
|
|
* this function will merge BL/WLs of child module when connect them to the
|
|
parent module
|
|
*
|
|
* QL Memory bank
|
|
* --------------
|
|
*
|
|
* config_bus (BL) config_bus (WL)
|
|
* | |
|
|
* parent | |
|
|
* +---------------------------------------------+
|
|
* | | | |
|
|
* | +---------------+ | |
|
|
* | | | | |
|
|
* | | +-----------|---+ |
|
|
* | | | | | |
|
|
* | v v v v |
|
|
* | +-------------------------------------+ |
|
|
* | | Child Mem 0 | ... | Child Mem N-1 | |
|
|
* | +-------------------------------------+ |
|
|
* | | | |
|
|
* | v v |
|
|
* | sram_out sram_outb |
|
|
* | |
|
|
* +---------------------------------------------+
|
|
|
|
*
|
|
**********************************************************************/
|
|
static void add_pb_module_nets_cmos_memory_config_bus(
|
|
ModuleManager& module_manager, DecoderLibrary& decoder_lib,
|
|
const ModuleId& parent_module, const e_config_protocol_type& sram_orgz_type,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
switch (sram_orgz_type) {
|
|
case CONFIG_MEM_SCAN_CHAIN: {
|
|
add_module_nets_cmos_memory_chain_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, config_child_type);
|
|
break;
|
|
}
|
|
case CONFIG_MEM_STANDALONE:
|
|
case CONFIG_MEM_QL_MEMORY_BANK:
|
|
add_module_nets_cmos_memory_bank_bl_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_BL,
|
|
config_child_type);
|
|
add_module_nets_cmos_memory_bank_wl_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WL,
|
|
config_child_type);
|
|
add_module_nets_cmos_memory_bank_wl_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WLR,
|
|
config_child_type);
|
|
break;
|
|
case CONFIG_MEM_MEMORY_BANK:
|
|
add_module_nets_cmos_flatten_memory_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_BL,
|
|
config_child_type);
|
|
add_module_nets_cmos_flatten_memory_config_bus(
|
|
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WL,
|
|
config_child_type);
|
|
break;
|
|
case CONFIG_MEM_FRAME_BASED:
|
|
add_module_nets_cmos_memory_frame_config_bus(
|
|
module_manager, decoder_lib, parent_module, config_child_type);
|
|
break;
|
|
default:
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
|
"Invalid type of SRAM organization!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* TODO:
|
|
* Add the port-to-port connection between a logic module
|
|
* and a memory module inside a primitive module
|
|
*
|
|
* Memory bank
|
|
* -----------
|
|
* config_bus (BL) config_bus (WL) shared_config_bugs(shared_BL/WLs)
|
|
* | | | |
|
|
* primitive | | | |
|
|
* +------------------------------------------------------------+
|
|
* | | | | | |
|
|
* | v v v v |
|
|
* | +----------------------------------------------------+ |
|
|
* | | ReRAM-based Memory Module | |
|
|
* | +----------------------------------------------------+ |
|
|
* | | | |
|
|
* | v v |
|
|
* | mem_out mem_outb |
|
|
* | |
|
|
* +------------------------------------------------------------+
|
|
*
|
|
**********************************************************************/
|
|
|
|
/********************************************************************
|
|
* Add the port-to-port connection between a memory module
|
|
* and the configuration bus of a primitive module
|
|
*
|
|
* Create nets to wire the control signals of memory module to
|
|
* the configuration ports of primitive module
|
|
*
|
|
* Primitive module
|
|
* +----------------------------+
|
|
* | +--------+ |
|
|
* config | | | |
|
|
* ports --->|--------------->| Memory | |
|
|
* | | Module | |
|
|
* | | | |
|
|
* | +--------+ |
|
|
* +----------------------------+
|
|
* The detailed config ports really depend on the type
|
|
* of SRAM organization.
|
|
*
|
|
* The config_bus in the argument is the reserved address of configuration
|
|
* bus in the parent_module for this memory module
|
|
*
|
|
* The configuration bus connection will depend not only
|
|
* the design technology of the memory cells but also the
|
|
* configuration styles of FPGA fabric.
|
|
* Here we will branch on the design technology
|
|
*
|
|
* Note: this function SHOULD be called after the pb_type_module is created
|
|
* and its child module (logic_module and memory_module) is created!
|
|
*******************************************************************/
|
|
void add_module_nets_memory_config_bus(
|
|
ModuleManager& module_manager, DecoderLibrary& decoder_lib,
|
|
const ModuleId& parent_module, const e_config_protocol_type& sram_orgz_type,
|
|
const e_circuit_model_design_tech& mem_tech,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
switch (mem_tech) {
|
|
case CIRCUIT_MODEL_DESIGN_CMOS:
|
|
add_module_nets_cmos_memory_config_bus(module_manager, decoder_lib,
|
|
parent_module, sram_orgz_type,
|
|
config_child_type);
|
|
break;
|
|
case CIRCUIT_MODEL_DESIGN_RRAM:
|
|
/* TODO: */
|
|
break;
|
|
default:
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
|
"Invalid type of memory design technology!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add the port-to-port connection between the configuration lines of
|
|
* a programmable block module (grid, CBX/CBY, SB) and its child module
|
|
*
|
|
* The configuration bus connection will depend not only
|
|
* the design technology of the memory cells but also the
|
|
* configuration styles of FPGA fabric.
|
|
* Here we will branch on the design technology
|
|
*
|
|
* Note: this function SHOULD be called after the pb_type_module is created
|
|
* and its child module (logic_module and memory_module) is created!
|
|
*******************************************************************/
|
|
void add_pb_module_nets_memory_config_bus(
|
|
ModuleManager& module_manager, DecoderLibrary& decoder_lib,
|
|
const ModuleId& parent_module, const e_config_protocol_type& sram_orgz_type,
|
|
const e_circuit_model_design_tech& mem_tech,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
switch (mem_tech) {
|
|
case CIRCUIT_MODEL_DESIGN_CMOS:
|
|
add_pb_module_nets_cmos_memory_config_bus(module_manager, decoder_lib,
|
|
parent_module, sram_orgz_type,
|
|
config_child_type);
|
|
break;
|
|
case CIRCUIT_MODEL_DESIGN_RRAM:
|
|
/* TODO: */
|
|
break;
|
|
default:
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
|
"Invalid type of memory design technology!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Find the size of shared(reserved) configuration ports for module
|
|
*******************************************************************/
|
|
size_t find_module_num_shared_config_bits(const ModuleManager& module_manager,
|
|
const ModuleId& module_id) {
|
|
std::vector<std::string> shared_config_port_names;
|
|
shared_config_port_names.push_back(
|
|
generate_reserved_sram_port_name(CIRCUIT_MODEL_PORT_BLB));
|
|
shared_config_port_names.push_back(
|
|
generate_reserved_sram_port_name(CIRCUIT_MODEL_PORT_WL));
|
|
size_t num_shared_config_bits =
|
|
0; /* By default it has zero configuration bits*/
|
|
|
|
/* Try to find these ports in the module manager */
|
|
for (const std::string& shared_config_port_name : shared_config_port_names) {
|
|
ModulePortId module_port_id =
|
|
module_manager.find_module_port(module_id, shared_config_port_name);
|
|
/* If the port does not exist, go to the next */
|
|
if (false ==
|
|
module_manager.valid_module_port_id(module_id, module_port_id)) {
|
|
continue;
|
|
}
|
|
/* The port exist, find the port size and update the num_config_bits if the
|
|
* size is larger */
|
|
BasicPort module_port =
|
|
module_manager.module_port(module_id, module_port_id);
|
|
num_shared_config_bits =
|
|
std::max((int)num_shared_config_bits, (int)module_port.get_width());
|
|
}
|
|
|
|
return num_shared_config_bits;
|
|
}
|
|
|
|
/********************************************************************
|
|
* Find the size of configuration ports for module
|
|
*******************************************************************/
|
|
size_t find_module_num_config_bits(
|
|
const ModuleManager& module_manager, const ModuleId& module_id,
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model,
|
|
const e_config_protocol_type& sram_orgz_type) {
|
|
std::vector<std::string> config_port_names =
|
|
generate_sram_port_names(circuit_lib, sram_model, sram_orgz_type);
|
|
size_t num_config_bits = 0; /* By default it has zero configuration bits*/
|
|
|
|
/* Try to find these ports in the module manager */
|
|
for (const std::string& config_port_name : config_port_names) {
|
|
ModulePortId module_port_id =
|
|
module_manager.find_module_port(module_id, config_port_name);
|
|
/* If the port does not exist, go to the next */
|
|
if (false ==
|
|
module_manager.valid_module_port_id(module_id, module_port_id)) {
|
|
continue;
|
|
}
|
|
/* The port exist, find the port size and update the num_config_bits if the
|
|
* size is larger */
|
|
BasicPort module_port =
|
|
module_manager.module_port(module_id, module_port_id);
|
|
num_config_bits =
|
|
std::max((int)num_config_bits, (int)module_port.get_width());
|
|
}
|
|
|
|
return num_config_bits;
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add General purpose I/O ports to the module:
|
|
* In this function, the following tasks are done:
|
|
* 1. find all the I/O ports from the child modules and build a list of it,
|
|
* 2. Merge all the I/O ports with the same name
|
|
* 3. add the ports to the pb_module
|
|
* 4. add module nets to connect to the GPIO ports of each sub module
|
|
*
|
|
* Module
|
|
* ----------------------+
|
|
* |
|
|
* child[0] |
|
|
* -----------+ |
|
|
* |----------+----> outputA[0]
|
|
* -----------+ |
|
|
* |
|
|
* child[1] |
|
|
* -----------+ |
|
|
* |----------+----> outputA[1]
|
|
* -----------+ |
|
|
|
|
*
|
|
* Note: This function should be call ONLY after all the sub modules (instances)
|
|
* have been added to the pb_module!
|
|
* Otherwise, some GPIO ports of the sub modules may be missed!
|
|
*******************************************************************/
|
|
static 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 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));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Record the port id for each type of GPIO port */
|
|
std::vector<ModulePortId> gpio_port_ids;
|
|
/* Add the gpio ports for the module */
|
|
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 */
|
|
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 (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) {
|
|
VTR_ASSERT(gpio_ports_to_add[iport].get_width() == gpio_port_lsb[iport]);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add GPIO ports to the module:
|
|
* In this function, the following tasks are done:
|
|
* 1. find all the GPIO ports from the child modules and build a list of it,
|
|
* 2. Merge all the GPIO ports with the same name
|
|
* 3. add the ports to the pb_module
|
|
* 4. add module nets to connect to the GPIO ports of each sub module
|
|
*
|
|
* Note: This function should be call ONLY after all the sub modules (instances)
|
|
* have been added to the pb_module!
|
|
* Otherwise, some GPIO ports of the sub modules may be missed!
|
|
*******************************************************************/
|
|
void add_module_gpio_ports_from_child_modules(ModuleManager& module_manager,
|
|
const ModuleId& module_id) {
|
|
add_module_io_ports_from_child_modules(module_manager, module_id,
|
|
ModuleManager::MODULE_GPIO_PORT);
|
|
|
|
add_module_io_ports_from_child_modules(module_manager, module_id,
|
|
ModuleManager::MODULE_GPIN_PORT);
|
|
|
|
add_module_io_ports_from_child_modules(module_manager, module_id,
|
|
ModuleManager::MODULE_GPOUT_PORT);
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add global input ports to the module:
|
|
* In this function, the following tasks are done:
|
|
* 1. find all the global input ports from the child modules and build a list of
|
|
*it,
|
|
* 2. add the input ports to the pb_module
|
|
* 3. add the module nets to connect the pb_module global ports to those of
|
|
*child modules
|
|
*
|
|
* Module
|
|
* +--------------------------
|
|
* | child[0]
|
|
* input_portA[0] ----+-+---->+----------
|
|
* | | |
|
|
* | | +----------
|
|
* | |
|
|
* | | child[1]
|
|
* | +---->+----------
|
|
* | |
|
|
* | +----------
|
|
*
|
|
* Note: This function should be call ONLY after all the sub modules (instances)
|
|
* have been added to the pb_module!
|
|
* Otherwise, some global ports of the sub modules may be missed!
|
|
*******************************************************************/
|
|
void add_module_global_input_ports_from_child_modules(
|
|
ModuleManager& module_manager, const ModuleId& module_id,
|
|
const std::vector<std::string>& port_name_to_ignore) {
|
|
std::vector<BasicPort> global_ports_to_add;
|
|
|
|
/* 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 global_port : module_manager.module_ports_by_type(
|
|
child, ModuleManager::MODULE_GLOBAL_PORT)) {
|
|
/* Search in the global port list to be added, if this is unique, we
|
|
* update the list */
|
|
std::vector<BasicPort>::iterator it = std::find(
|
|
global_ports_to_add.begin(), global_ports_to_add.end(), global_port);
|
|
if (it != global_ports_to_add.end()) {
|
|
continue;
|
|
}
|
|
/* Reach here, this is an unique global port, update the list
|
|
* Final check: ignore those in the blacklist
|
|
*/
|
|
if (std::find(port_name_to_ignore.begin(), port_name_to_ignore.end(),
|
|
global_port.get_name()) == port_name_to_ignore.end()) {
|
|
global_ports_to_add.push_back(global_port);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Record the port id for each type of global port */
|
|
std::vector<ModulePortId> global_port_ids;
|
|
/* Add the global ports for the module */
|
|
for (const BasicPort& global_port_to_add : global_ports_to_add) {
|
|
ModulePortId port_id = module_manager.add_port(
|
|
module_id, global_port_to_add, ModuleManager::MODULE_GLOBAL_PORT);
|
|
global_port_ids.push_back(port_id);
|
|
}
|
|
|
|
/* Count the number of sinks for each global port */
|
|
std::map<ModulePortId, size_t> port_sink_count;
|
|
for (const ModuleId& child : module_manager.child_modules(module_id)) {
|
|
/* Find all the global ports, whose port type is special */
|
|
for (ModulePortId child_global_port_id :
|
|
module_manager.module_port_ids_by_type(
|
|
child, ModuleManager::MODULE_GLOBAL_PORT)) {
|
|
BasicPort child_global_port =
|
|
module_manager.module_port(child, child_global_port_id);
|
|
/* Skip if it is in the ignore list */
|
|
if (std::find(port_name_to_ignore.begin(), port_name_to_ignore.end(),
|
|
child_global_port.get_name()) !=
|
|
port_name_to_ignore.end()) {
|
|
continue;
|
|
}
|
|
|
|
/* Search in the global port list to be added, find the port id */
|
|
std::vector<BasicPort>::iterator it =
|
|
std::find(global_ports_to_add.begin(), global_ports_to_add.end(),
|
|
child_global_port);
|
|
VTR_ASSERT(it != global_ports_to_add.end());
|
|
ModulePortId module_global_port_id =
|
|
global_port_ids[it - global_ports_to_add.begin()];
|
|
|
|
port_sink_count[module_global_port_id] +=
|
|
module_manager.num_instance(module_id, child);
|
|
}
|
|
}
|
|
|
|
/* Add module nets to connect the global ports of the module to the global
|
|
* ports of the sub module */
|
|
/* Iterate over the child modules */
|
|
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_global_port_id :
|
|
module_manager.module_port_ids_by_type(
|
|
child, ModuleManager::MODULE_GLOBAL_PORT)) {
|
|
BasicPort child_global_port =
|
|
module_manager.module_port(child, child_global_port_id);
|
|
/* Skip if it is in the ignore list */
|
|
if (std::find(port_name_to_ignore.begin(), port_name_to_ignore.end(),
|
|
child_global_port.get_name()) !=
|
|
port_name_to_ignore.end()) {
|
|
continue;
|
|
}
|
|
|
|
/* Search in the global port list to be added, find the port id */
|
|
std::vector<BasicPort>::iterator it =
|
|
std::find(global_ports_to_add.begin(), global_ports_to_add.end(),
|
|
child_global_port);
|
|
VTR_ASSERT(it != global_ports_to_add.end());
|
|
ModulePortId module_global_port_id =
|
|
global_port_ids[it - global_ports_to_add.begin()];
|
|
BasicPort module_global_port =
|
|
module_manager.module_port(module_id, module_global_port_id);
|
|
/* The global ports should match in size */
|
|
VTR_ASSERT(module_global_port.get_width() ==
|
|
child_global_port.get_width());
|
|
/* For each pin of the child port, create a net and do wiring */
|
|
for (size_t pin_id = 0; pin_id < child_global_port.pins().size();
|
|
++pin_id) {
|
|
/* Reach here, it means this is the port we want, create a net and
|
|
* configure its source and sink */
|
|
ModuleNetId net = create_module_source_pin_net(
|
|
module_manager, module_id, module_id, 0, module_global_port_id,
|
|
module_global_port.pins()[pin_id]);
|
|
module_manager.reserve_module_net_sinks(
|
|
module_id, net, port_sink_count[module_global_port_id]);
|
|
module_manager.add_module_net_sink(
|
|
module_id, net, child, child_instance, child_global_port_id,
|
|
child_global_port.pins()[pin_id]);
|
|
/* We finish for this child gpio port */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add global ports to the module:
|
|
* In this function, we will add global input ports and global output ports
|
|
* which are collected from the child modules
|
|
*
|
|
* - Input ports: the input ports will be uniquified by names
|
|
* Ports with the same name will be merged to the same pin
|
|
* See details inside the function
|
|
*
|
|
* - Output ports: the output ports will be uniquified by names
|
|
* Different from the input ports, output ports
|
|
* with the same name will be merged but will have indepedent
|
|
*pins See details inside the function
|
|
*
|
|
* Note: This function should be call ONLY after all the sub modules (instances)
|
|
* have been added to the pb_module!
|
|
* Otherwise, some global ports of the sub modules may be missed!
|
|
*******************************************************************/
|
|
void add_module_global_ports_from_child_modules(
|
|
ModuleManager& module_manager, const ModuleId& module_id,
|
|
const std::vector<std::string>& port_name_to_ignore) {
|
|
/* Input ports */
|
|
add_module_global_input_ports_from_child_modules(module_manager, module_id,
|
|
port_name_to_ignore);
|
|
}
|
|
|
|
/********************************************************************
|
|
* Find the number of shared configuration bits for a module
|
|
* by selected the maximum number of shared configuration bits of child modules
|
|
*
|
|
* Note: This function should be call ONLY after all the sub modules (instances)
|
|
* have been added to the pb_module!
|
|
* Otherwise, some global ports of the sub modules may be missed!
|
|
*******************************************************************/
|
|
size_t find_module_num_shared_config_bits_from_child_modules(
|
|
ModuleManager& module_manager, const ModuleId& module_id) {
|
|
size_t num_shared_config_bits = 0;
|
|
|
|
/* Iterate over the child modules */
|
|
for (const ModuleId& child : module_manager.child_modules(module_id)) {
|
|
num_shared_config_bits =
|
|
std::max((int)num_shared_config_bits,
|
|
(int)find_module_num_shared_config_bits(module_manager, child));
|
|
}
|
|
|
|
return num_shared_config_bits;
|
|
}
|
|
|
|
/********************************************************************
|
|
* Find the number of configuration bits for a module
|
|
* by summing up the number of configuration bits of child modules
|
|
*
|
|
* Note: This function should be call ONLY after all the sub modules (instances)
|
|
* have been added to the pb_module!
|
|
* Otherwise, some global ports of the sub modules may be missed!
|
|
*******************************************************************/
|
|
size_t find_module_num_config_bits_from_child_modules(
|
|
ModuleManager& module_manager, const ModuleId& module_id,
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model,
|
|
const e_config_protocol_type& sram_orgz_type,
|
|
const ModuleManager::e_config_child_type& config_child_type) {
|
|
size_t num_config_bits = 0;
|
|
|
|
switch (sram_orgz_type) {
|
|
case CONFIG_MEM_FEEDTHROUGH:
|
|
case CONFIG_MEM_STANDALONE:
|
|
case CONFIG_MEM_SCAN_CHAIN:
|
|
case CONFIG_MEM_QL_MEMORY_BANK:
|
|
case CONFIG_MEM_MEMORY_BANK: {
|
|
/* For scan-chain, standalone and memory bank configuration protocol
|
|
* The number of configuration bits is the sum of configuration bits
|
|
* per configurable children
|
|
*/
|
|
for (const ModuleId& child :
|
|
module_manager.configurable_children(module_id, config_child_type)) {
|
|
num_config_bits += find_module_num_config_bits(
|
|
module_manager, child, circuit_lib, sram_model, sram_orgz_type);
|
|
}
|
|
break;
|
|
}
|
|
case CONFIG_MEM_FRAME_BASED: {
|
|
/* For frame-based configuration protocol
|
|
* The number of configuration bits is the sum of
|
|
* - the maximum of configuration bits among configurable children
|
|
* - and the number of configurable children
|
|
*/
|
|
for (const ModuleId& child :
|
|
module_manager.configurable_children(module_id, config_child_type)) {
|
|
size_t temp_num_config_bits = find_module_num_config_bits(
|
|
module_manager, child, circuit_lib, sram_model, sram_orgz_type);
|
|
num_config_bits =
|
|
std::max((int)temp_num_config_bits, (int)num_config_bits);
|
|
}
|
|
|
|
/* If there are more than 2 configurable children, we need a decoder
|
|
* Otherwise, we can just short wire the address port to the children
|
|
*/
|
|
if (1 < module_manager.num_configurable_children(module_id,
|
|
config_child_type)) {
|
|
num_config_bits += find_mux_local_decoder_addr_size(
|
|
module_manager.num_configurable_children(module_id,
|
|
config_child_type));
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
VTR_LOG_ERROR("Invalid type of SRAM organization !\n");
|
|
exit(1);
|
|
}
|
|
|
|
return num_config_bits;
|
|
}
|
|
|
|
/********************************************************************
|
|
* Try to create a net for the source pin
|
|
* This function will try
|
|
* - Find if there is already a net created whose source is the pin
|
|
* If so, it will return the net id
|
|
* - If not, it will create a net and configure its source
|
|
*******************************************************************/
|
|
ModuleNetId create_module_source_pin_net(ModuleManager& module_manager,
|
|
const ModuleId& cur_module_id,
|
|
const ModuleId& src_module_id,
|
|
const size_t& src_instance_id,
|
|
const ModulePortId& src_module_port_id,
|
|
const size_t& src_pin_id) {
|
|
ModuleNetId net = module_manager.module_instance_port_net(
|
|
cur_module_id, src_module_id, src_instance_id, src_module_port_id,
|
|
src_pin_id);
|
|
if (ModuleNetId::INVALID() == net) {
|
|
net = module_manager.create_module_net(cur_module_id);
|
|
module_manager.add_module_net_source(cur_module_id, net, src_module_id,
|
|
src_instance_id, src_module_port_id,
|
|
src_pin_id);
|
|
}
|
|
|
|
return net;
|
|
}
|
|
|
|
/********************************************************************
|
|
* Add a bus of nets to a module (cur_module_id)
|
|
* Note:
|
|
* - both src and des module should exist in the module manager
|
|
* - src_module should be the cur_module or a child of it
|
|
* - des_module should be the cur_module or a child of it
|
|
* - src_instance should be valid and des_instance should be valid as well
|
|
* - src port size should match the des port size
|
|
*
|
|
*******************************************************************/
|
|
void add_module_bus_nets(
|
|
ModuleManager& module_manager, const ModuleId& cur_module_id,
|
|
const ModuleId& src_module_id, const size_t& src_instance_id,
|
|
const ModulePortId& src_module_port_id, const ModuleId& des_module_id,
|
|
const size_t& des_instance_id, const ModulePortId& des_module_port_id) {
|
|
VTR_ASSERT(true == module_manager.valid_module_id(cur_module_id));
|
|
VTR_ASSERT(true == module_manager.valid_module_id(src_module_id));
|
|
VTR_ASSERT(true == module_manager.valid_module_id(des_module_id));
|
|
|
|
VTR_ASSERT(true == module_manager.valid_module_port_id(src_module_id,
|
|
src_module_port_id));
|
|
VTR_ASSERT(true == module_manager.valid_module_port_id(des_module_id,
|
|
des_module_port_id));
|
|
|
|
if (src_module_id == cur_module_id) {
|
|
VTR_ASSERT(0 == src_instance_id);
|
|
} else {
|
|
VTR_ASSERT(src_instance_id <
|
|
module_manager.num_instance(cur_module_id, src_module_id));
|
|
}
|
|
|
|
if (des_module_id == cur_module_id) {
|
|
VTR_ASSERT(0 == des_instance_id);
|
|
} else {
|
|
VTR_ASSERT(des_instance_id <
|
|
module_manager.num_instance(cur_module_id, des_module_id));
|
|
}
|
|
|
|
const BasicPort& src_port =
|
|
module_manager.module_port(src_module_id, src_module_port_id);
|
|
const BasicPort& des_port =
|
|
module_manager.module_port(des_module_id, des_module_port_id);
|
|
|
|
if (src_port.get_width() != des_port.get_width()) {
|
|
VTR_LOGF_ERROR(
|
|
__FILE__, __LINE__,
|
|
"Unmatched port size: src_port %s is %lu while des_port %s is %lu!\n",
|
|
src_port.get_name().c_str(), src_port.get_width(),
|
|
des_port.get_name().c_str(), des_port.get_width());
|
|
exit(1);
|
|
}
|
|
|
|
/* Create a net for each pin */
|
|
for (size_t pin_id = 0; pin_id < src_port.pins().size(); ++pin_id) {
|
|
ModuleNetId net = create_module_source_pin_net(
|
|
module_manager, cur_module_id, src_module_id, src_instance_id,
|
|
src_module_port_id, src_port.pins()[pin_id]);
|
|
VTR_ASSERT(ModuleNetId::INVALID() != net);
|
|
|
|
/* Configure the net sink */
|
|
module_manager.add_module_net_sink(cur_module_id, net, des_module_id,
|
|
des_instance_id, des_module_port_id,
|
|
des_port.pins()[pin_id]);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* TODO:
|
|
* Add the port-to-port connection between a logic module
|
|
* and a memory module inside a primitive module
|
|
*
|
|
* Create nets to wire the formal verification ports of
|
|
* primitive module to SRAM ports of logic module
|
|
*
|
|
* Primitive module
|
|
*
|
|
* formal_port_sram
|
|
* +-----------------------------------------------+
|
|
* | ^ |
|
|
* | +---------+ | +--------+ |
|
|
* | | | SRAM | | | |
|
|
* | | Logic |--------+--->| Memory | |
|
|
* | | Module | SRAMb | Module | |
|
|
* | | |--------+--->| | |
|
|
* | +---------+ | +--------+ |
|
|
* | v |
|
|
* +-----------------------------------------------+
|
|
* formal_port_sramb
|
|
*
|
|
*******************************************************************/
|
|
|
|
} /* end namespace openfpga */
|