[Engine] Place QL memory bank source codes in a separated source file so that integration to OpenFPGA open-source version is easier
This commit is contained in:
parent
cf2e479d18
commit
ed80d6b3f4
|
@ -422,6 +422,7 @@ int build_top_module(ModuleManager& module_manager,
|
||||||
if (0 < module_manager.configurable_children(top_module).size()) {
|
if (0 < module_manager.configurable_children(top_module).size()) {
|
||||||
add_top_module_nets_memory_config_bus(module_manager, decoder_lib,
|
add_top_module_nets_memory_config_bus(module_manager, decoder_lib,
|
||||||
top_module,
|
top_module,
|
||||||
|
circuit_lib, sram_model,
|
||||||
config_protocol, circuit_lib.design_tech_type(sram_model),
|
config_protocol, circuit_lib.design_tech_type(sram_model),
|
||||||
top_module_num_config_bits);
|
top_module_num_config_bits);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "decoder_library_utils.h"
|
#include "decoder_library_utils.h"
|
||||||
#include "module_manager_utils.h"
|
#include "module_manager_utils.h"
|
||||||
#include "build_decoder_modules.h"
|
#include "build_decoder_modules.h"
|
||||||
|
#include "build_top_module_memory_bank.h"
|
||||||
#include "build_top_module_memory.h"
|
#include "build_top_module_memory.h"
|
||||||
|
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
|
@ -689,8 +690,8 @@ TopModuleNumConfigBits find_top_module_regional_num_config_bit(const ModuleManag
|
||||||
for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) {
|
for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) {
|
||||||
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
|
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
|
||||||
vtr::Point<int> coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id];
|
vtr::Point<int> coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id];
|
||||||
num_bls[coord.x()] = std::max(num_bls[coord.x()], find_memory_decoder_addr_size(find_module_num_config_bits(module_manager, child_module, circuit_lib, sram_model, config_protocol_type)));
|
num_bls[coord.x()] = std::max(num_bls[coord.x()], find_memory_decoder_data_size(find_module_num_config_bits(module_manager, child_module, circuit_lib, sram_model, config_protocol_type)));
|
||||||
num_wls[coord.y()] = std::max(num_wls[coord.y()], find_memory_decoder_addr_size(find_module_num_config_bits(module_manager, child_module, circuit_lib, sram_model, config_protocol_type)));
|
num_wls[coord.y()] = std::max(num_wls[coord.y()], find_memory_decoder_data_size(find_module_num_config_bits(module_manager, child_module, circuit_lib, sram_model, config_protocol_type)));
|
||||||
for (const auto& kv : num_bls) {
|
for (const auto& kv : num_bls) {
|
||||||
num_config_bits[config_region].first += kv.first;
|
num_config_bits[config_region].first += kv.first;
|
||||||
}
|
}
|
||||||
|
@ -850,7 +851,7 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
||||||
/* BL address size is the largest among all the regions */
|
/* BL address size is the largest among all the regions */
|
||||||
size_t bl_addr_size = 0;
|
size_t bl_addr_size = 0;
|
||||||
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
|
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
|
||||||
bl_addr_size = std::max(bl_addr_size, num_config_bits[config_region].first);
|
bl_addr_size = std::max(bl_addr_size, find_memory_decoder_addr_size(num_config_bits[config_region].first));
|
||||||
}
|
}
|
||||||
BasicPort bl_addr_port(std::string(DECODER_BL_ADDRESS_PORT_NAME), bl_addr_size);
|
BasicPort bl_addr_port(std::string(DECODER_BL_ADDRESS_PORT_NAME), bl_addr_size);
|
||||||
module_manager.add_port(module_id, bl_addr_port, ModuleManager::MODULE_INPUT_PORT);
|
module_manager.add_port(module_id, bl_addr_port, ModuleManager::MODULE_INPUT_PORT);
|
||||||
|
@ -858,7 +859,7 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
||||||
/* WL address size is the largest among all the regions */
|
/* WL address size is the largest among all the regions */
|
||||||
size_t wl_addr_size = 0;
|
size_t wl_addr_size = 0;
|
||||||
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
|
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
|
||||||
wl_addr_size = std::max(wl_addr_size, num_config_bits[config_region].second);
|
wl_addr_size = std::max(wl_addr_size, find_memory_decoder_addr_size(num_config_bits[config_region].second));
|
||||||
}
|
}
|
||||||
BasicPort wl_addr_port(std::string(DECODER_WL_ADDRESS_PORT_NAME), wl_addr_size);
|
BasicPort wl_addr_port(std::string(DECODER_WL_ADDRESS_PORT_NAME), wl_addr_size);
|
||||||
module_manager.add_port(module_id, wl_addr_port, ModuleManager::MODULE_INPUT_PORT);
|
module_manager.add_port(module_id, wl_addr_port, ModuleManager::MODULE_INPUT_PORT);
|
||||||
|
@ -1750,6 +1751,8 @@ static
|
||||||
void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
const ModuleId& parent_module,
|
const ModuleId& parent_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
const ConfigProtocol& config_protocol,
|
const ConfigProtocol& config_protocol,
|
||||||
const TopModuleNumConfigBits& num_config_bits) {
|
const TopModuleNumConfigBits& num_config_bits) {
|
||||||
switch (config_protocol.type()) {
|
switch (config_protocol.type()) {
|
||||||
|
@ -1766,6 +1769,9 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
||||||
case CONFIG_MEM_MEMORY_BANK:
|
case CONFIG_MEM_MEMORY_BANK:
|
||||||
add_top_module_nets_cmos_memory_bank_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
|
add_top_module_nets_cmos_memory_bank_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
|
||||||
break;
|
break;
|
||||||
|
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||||
|
add_top_module_nets_cmos_ql_memory_bank_config_bus(module_manager, decoder_lib, parent_module, circuit_lib, sram_model, num_config_bits);
|
||||||
|
break;
|
||||||
case CONFIG_MEM_FRAME_BASED:
|
case CONFIG_MEM_FRAME_BASED:
|
||||||
add_top_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
|
add_top_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
|
||||||
break;
|
break;
|
||||||
|
@ -1811,6 +1817,8 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
||||||
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
const ModuleId& parent_module,
|
const ModuleId& parent_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
const ConfigProtocol& config_protocol,
|
const ConfigProtocol& config_protocol,
|
||||||
const e_circuit_model_design_tech& mem_tech,
|
const e_circuit_model_design_tech& mem_tech,
|
||||||
const TopModuleNumConfigBits& num_config_bits) {
|
const TopModuleNumConfigBits& num_config_bits) {
|
||||||
|
@ -1820,7 +1828,9 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||||
switch (mem_tech) {
|
switch (mem_tech) {
|
||||||
case CIRCUIT_MODEL_DESIGN_CMOS:
|
case CIRCUIT_MODEL_DESIGN_CMOS:
|
||||||
add_top_module_nets_cmos_memory_config_bus(module_manager, decoder_lib,
|
add_top_module_nets_cmos_memory_config_bus(module_manager, decoder_lib,
|
||||||
parent_module,
|
parent_module,
|
||||||
|
circuit_lib,
|
||||||
|
sram_model,
|
||||||
config_protocol,
|
config_protocol,
|
||||||
num_config_bits);
|
num_config_bits);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "device_rr_gsb.h"
|
#include "device_rr_gsb.h"
|
||||||
#include "fabric_key.h"
|
#include "fabric_key.h"
|
||||||
#include "config_protocol.h"
|
#include "config_protocol.h"
|
||||||
|
#include "build_top_module_memory_utils.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Function declaration
|
* Function declaration
|
||||||
|
@ -26,8 +27,6 @@
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
typedef vtr::vector<ConfigRegionId, std::pair<size_t, size_t>> TopModuleNumConfigBits;
|
|
||||||
|
|
||||||
void organize_top_module_memory_modules(ModuleManager& module_manager,
|
void organize_top_module_memory_modules(ModuleManager& module_manager,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
|
@ -66,6 +65,8 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
||||||
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
const ModuleId& parent_module,
|
const ModuleId& parent_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
const ConfigProtocol& config_protocol,
|
const ConfigProtocol& config_protocol,
|
||||||
const e_circuit_model_design_tech& mem_tech,
|
const e_circuit_model_design_tech& mem_tech,
|
||||||
const TopModuleNumConfigBits& num_config_bits);
|
const TopModuleNumConfigBits& num_config_bits);
|
||||||
|
|
|
@ -0,0 +1,383 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes functions that are used to organize memories
|
||||||
|
* in the top module of FPGA fabric
|
||||||
|
*******************************************************************/
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
/* Headers from vtrutil library */
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "vtr_log.h"
|
||||||
|
#include "vtr_time.h"
|
||||||
|
|
||||||
|
/* Headers from vpr library */
|
||||||
|
#include "vpr_utils.h"
|
||||||
|
|
||||||
|
/* Headers from openfpgashell library */
|
||||||
|
#include "command_exit_codes.h"
|
||||||
|
|
||||||
|
#include "rr_gsb_utils.h"
|
||||||
|
#include "openfpga_reserved_words.h"
|
||||||
|
#include "openfpga_naming.h"
|
||||||
|
|
||||||
|
#include "memory_utils.h"
|
||||||
|
#include "decoder_library_utils.h"
|
||||||
|
#include "module_manager_utils.h"
|
||||||
|
#include "build_decoder_modules.h"
|
||||||
|
#include "build_top_module_memory_bank.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Top-level function to add nets for quicklogic memory banks
|
||||||
|
* Each configuration region has independent memory bank circuitry
|
||||||
|
* - Find the number of BLs and WLs required for each region
|
||||||
|
* - Create BL and WL decoders, and add them to decoder library
|
||||||
|
* - Create nets to connect from top-level module inputs to inputs of decoders
|
||||||
|
* - Create nets to connect from outputs of decoders to BL/WL of configurable children
|
||||||
|
*
|
||||||
|
* Detailed schematic of how memory banks are connected in the top-level:
|
||||||
|
* Consider a random Region X, local BL address lines are aligned to the LSB of the
|
||||||
|
* top-level BL address lines
|
||||||
|
*
|
||||||
|
* top_bl_addr[N-1:0]
|
||||||
|
* ^
|
||||||
|
* | local_bl_addr[N-1:0]
|
||||||
|
* |
|
||||||
|
* +-----+------------------+
|
||||||
|
* | | |
|
||||||
|
* | +-------------------+ |
|
||||||
|
* | | Word Line Decoder | |
|
||||||
|
* | +-------------------+ |
|
||||||
|
* | |
|
||||||
|
*
|
||||||
|
* The BL/WL decoders should have the same circuit designs no matter what region
|
||||||
|
* they are placed even when the number of configuration bits are different
|
||||||
|
* from one region to another!
|
||||||
|
* This is designed to avoid any address collision between memory banks
|
||||||
|
* since they are programmed in the same clock cycle
|
||||||
|
* For example:
|
||||||
|
* - Memory Bank A has 36 memory cells.
|
||||||
|
* Its BL decoder has 3 address bit and 6 data output bit
|
||||||
|
* Its WL decoder has 3 address bit and 6 data output bit
|
||||||
|
* - Memory Bank B has 16 memory cells.
|
||||||
|
* Its BL decoder has 2 address bit and 4 data output bit
|
||||||
|
* Its WL decoder has 2 address bit and 4 data output bit
|
||||||
|
* - If we try to program the 36th memory cell in bank A
|
||||||
|
* the BL address will be 3'b110
|
||||||
|
* the WL address will be 3'b110
|
||||||
|
* the data input will be 1'b0
|
||||||
|
* - If we try to program the 4th memory cell in bank A
|
||||||
|
* the BL address will be 3'b010
|
||||||
|
* the WL address will be 3'b010
|
||||||
|
* the data input will be 1'b1
|
||||||
|
* However, in both cases, this will trigger a parasitic programming in bank B
|
||||||
|
* the BL address will be 2'b10
|
||||||
|
* the WL address will be 2'b10
|
||||||
|
* Assume the data input is expected to be 1'b1 for bank B
|
||||||
|
* but it will be overwritten to 1'b0 when programming the 36th cell in bank A!
|
||||||
|
*
|
||||||
|
* Detailed schematic of each memory bank:
|
||||||
|
* @note The numbers are just made to show a simplified example, practical cases are more complicated!
|
||||||
|
*
|
||||||
|
* WL_enable WL address
|
||||||
|
* | |
|
||||||
|
* v v
|
||||||
|
* +-----------------------------------------------+
|
||||||
|
* | Word Line Decoder |
|
||||||
|
* +-----------------------------------------------+
|
||||||
|
* +---------+ | | |
|
||||||
|
* BL | | | | |
|
||||||
|
* enable ---->| |-----------+---------------+---- ... |------+--> BL[0:2]
|
||||||
|
* | | | | | | | |
|
||||||
|
* | | | v | v | v
|
||||||
|
* | Bit | | +-------+ | +-------+ | +------+
|
||||||
|
* BL | Line | +-->| SRAM | +-->| SRAM | +->| SRAM |
|
||||||
|
* address ---->| Decoder | | | [0:8] | | | [0:5] | ... | | [0:7]|
|
||||||
|
* | | | +-------+ | +-------+ | +------+
|
||||||
|
* | | | | |
|
||||||
|
* | |-----------+--------------+--------- | -----+--> BL[0:9]
|
||||||
|
* | | | | | | | |
|
||||||
|
* | | | v | v | v
|
||||||
|
* | | | +-------+ | +-------+ | +-------+
|
||||||
|
* | | +-->| SRAM | | | SRAM | +->| SRAM |
|
||||||
|
* | | | | [0:80]| | | [0:63]| ... | | [0:31]|
|
||||||
|
* | | | +-------+ | +-------+ | +-------+
|
||||||
|
* | | | |
|
||||||
|
* | | | ... ... ... | ...
|
||||||
|
* | | | | |
|
||||||
|
* | |-----------+---------------+---- --- | -----+--> BL[0:3]
|
||||||
|
* | | | | | | | |
|
||||||
|
* | | | v | v | v
|
||||||
|
* | | | +-------+ | +-------+ | +-------+
|
||||||
|
* | | +-->| SRAM | +-->| SRAM | +->| SRAM |
|
||||||
|
* | | | |[0:5] | | | [0:8] | ... | | [0:2] |
|
||||||
|
* | | | +-------+ | +-------+ | +-------+
|
||||||
|
* BL | | v v v
|
||||||
|
* data_in ---->| | WL[0:9] WL[0:7] WL[0:4]
|
||||||
|
* +---------+
|
||||||
|
*
|
||||||
|
**********************************************************************/
|
||||||
|
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager,
|
||||||
|
DecoderLibrary& decoder_lib,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
|
const TopModuleNumConfigBits& num_config_bits) {
|
||||||
|
/* Find Enable port from the top-level module */
|
||||||
|
ModulePortId en_port = module_manager.find_module_port(top_module, std::string(DECODER_ENABLE_PORT_NAME));
|
||||||
|
BasicPort en_port_info = module_manager.module_port(top_module, en_port);
|
||||||
|
|
||||||
|
/* Find data-in port from the top-level module */
|
||||||
|
ModulePortId din_port = module_manager.find_module_port(top_module, std::string(DECODER_DATA_IN_PORT_NAME));
|
||||||
|
BasicPort din_port_info = module_manager.module_port(top_module, din_port);
|
||||||
|
|
||||||
|
/* Data in port should match the number of configuration regions */
|
||||||
|
VTR_ASSERT(din_port_info.get_width() == module_manager.regions(top_module).size());
|
||||||
|
|
||||||
|
/* Find BL and WL address port from the top-level module */
|
||||||
|
ModulePortId bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME));
|
||||||
|
BasicPort bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port);
|
||||||
|
|
||||||
|
ModulePortId wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME));
|
||||||
|
BasicPort wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port);
|
||||||
|
|
||||||
|
/* Find the top-level number of BLs and WLs required to access each memory bit */
|
||||||
|
size_t bl_addr_size = bl_addr_port_info.get_width();
|
||||||
|
size_t wl_addr_size = wl_addr_port_info.get_width();
|
||||||
|
|
||||||
|
/* Each memory bank has a unified number of BL/WLs */
|
||||||
|
size_t num_bls = 0;
|
||||||
|
for (const auto& curr_config_bits : num_config_bits) {
|
||||||
|
num_bls = std::max(num_bls, find_memory_decoder_data_size(curr_config_bits.first));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t num_wls = 0;
|
||||||
|
for (const auto& curr_config_bits : num_config_bits) {
|
||||||
|
num_wls = std::max(num_wls, find_memory_decoder_data_size(curr_config_bits.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create separated memory bank circuitry, i.e., BL/WL decoders for each region */
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||||
|
/**************************************************************
|
||||||
|
* Add the BL decoder module
|
||||||
|
* Search the decoder library
|
||||||
|
* If we find one, we use the module.
|
||||||
|
* Otherwise, we create one and add it to the decoder library
|
||||||
|
*/
|
||||||
|
DecoderId bl_decoder_id = decoder_lib.find_decoder(bl_addr_size, num_bls,
|
||||||
|
true, true, false);
|
||||||
|
if (DecoderId::INVALID() == bl_decoder_id) {
|
||||||
|
bl_decoder_id = decoder_lib.add_decoder(bl_addr_size, num_bls, true, true, false);
|
||||||
|
}
|
||||||
|
VTR_ASSERT(DecoderId::INVALID() != bl_decoder_id);
|
||||||
|
|
||||||
|
/* Create a module if not existed yet */
|
||||||
|
std::string bl_decoder_module_name = generate_memory_decoder_with_data_in_subckt_name(bl_addr_size, num_bls);
|
||||||
|
ModuleId bl_decoder_module = module_manager.find_module(bl_decoder_module_name);
|
||||||
|
if (ModuleId::INVALID() == bl_decoder_module) {
|
||||||
|
/* BL decoder has the same ports as the frame-based decoders
|
||||||
|
* We reuse it here
|
||||||
|
*/
|
||||||
|
bl_decoder_module = build_bl_memory_decoder_module(module_manager,
|
||||||
|
decoder_lib,
|
||||||
|
bl_decoder_id);
|
||||||
|
}
|
||||||
|
VTR_ASSERT(ModuleId::INVALID() != bl_decoder_module);
|
||||||
|
size_t curr_bl_decoder_instance_id = module_manager.num_instance(top_module, bl_decoder_module);
|
||||||
|
module_manager.add_child_module(top_module, bl_decoder_module);
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Add the WL decoder module
|
||||||
|
* Search the decoder library
|
||||||
|
* If we find one, we use the module.
|
||||||
|
* Otherwise, we create one and add it to the decoder library
|
||||||
|
*/
|
||||||
|
DecoderId wl_decoder_id = decoder_lib.find_decoder(wl_addr_size, num_wls,
|
||||||
|
true, false, false);
|
||||||
|
if (DecoderId::INVALID() == wl_decoder_id) {
|
||||||
|
wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false);
|
||||||
|
}
|
||||||
|
VTR_ASSERT(DecoderId::INVALID() != wl_decoder_id);
|
||||||
|
|
||||||
|
/* Create a module if not existed yet */
|
||||||
|
std::string wl_decoder_module_name = generate_memory_decoder_subckt_name(wl_addr_size, num_wls);
|
||||||
|
ModuleId wl_decoder_module = module_manager.find_module(wl_decoder_module_name);
|
||||||
|
if (ModuleId::INVALID() == wl_decoder_module) {
|
||||||
|
/* BL decoder has the same ports as the frame-based decoders
|
||||||
|
* We reuse it here
|
||||||
|
*/
|
||||||
|
wl_decoder_module = build_wl_memory_decoder_module(module_manager,
|
||||||
|
decoder_lib,
|
||||||
|
wl_decoder_id);
|
||||||
|
}
|
||||||
|
VTR_ASSERT(ModuleId::INVALID() != wl_decoder_module);
|
||||||
|
size_t curr_wl_decoder_instance_id = module_manager.num_instance(top_module, wl_decoder_module);
|
||||||
|
module_manager.add_child_module(top_module, wl_decoder_module);
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Add module nets from the top module to BL decoder's inputs
|
||||||
|
*/
|
||||||
|
ModulePortId bl_decoder_en_port = module_manager.find_module_port(bl_decoder_module, std::string(DECODER_ENABLE_PORT_NAME));
|
||||||
|
BasicPort bl_decoder_en_port_info = module_manager.module_port(bl_decoder_module, bl_decoder_en_port);
|
||||||
|
|
||||||
|
ModulePortId bl_decoder_addr_port = module_manager.find_module_port(bl_decoder_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
||||||
|
BasicPort bl_decoder_addr_port_info = module_manager.module_port(bl_decoder_module, bl_decoder_addr_port);
|
||||||
|
|
||||||
|
ModulePortId bl_decoder_din_port = module_manager.find_module_port(bl_decoder_module, std::string(DECODER_DATA_IN_PORT_NAME));
|
||||||
|
BasicPort bl_decoder_din_port_info = module_manager.module_port(bl_decoder_module, bl_decoder_din_port);
|
||||||
|
|
||||||
|
/* Data in port of the local BL decoder should always be 1 */
|
||||||
|
VTR_ASSERT(1 == bl_decoder_din_port_info.get_width());
|
||||||
|
|
||||||
|
/* Top module Enable port -> BL Decoder Enable port */
|
||||||
|
add_module_bus_nets(module_manager,
|
||||||
|
top_module,
|
||||||
|
top_module, 0, en_port,
|
||||||
|
bl_decoder_module, curr_bl_decoder_instance_id, bl_decoder_en_port);
|
||||||
|
|
||||||
|
/* Top module Address port -> BL Decoder Address port */
|
||||||
|
add_module_bus_nets(module_manager,
|
||||||
|
top_module,
|
||||||
|
top_module, 0, bl_addr_port,
|
||||||
|
bl_decoder_module, curr_bl_decoder_instance_id, bl_decoder_addr_port);
|
||||||
|
|
||||||
|
/* Top module data_in port -> BL Decoder data_in port:
|
||||||
|
* Note that each region has independent data_in connection from the top-level module
|
||||||
|
* The pin index is the configuration region index
|
||||||
|
*/
|
||||||
|
ModuleNetId din_net = create_module_source_pin_net(module_manager, top_module,
|
||||||
|
top_module, 0,
|
||||||
|
din_port,
|
||||||
|
din_port_info.pins()[size_t(config_region)]);
|
||||||
|
VTR_ASSERT(ModuleNetId::INVALID() != din_net);
|
||||||
|
|
||||||
|
/* Configure the net sink */
|
||||||
|
module_manager.add_module_net_sink(top_module, din_net, bl_decoder_module, curr_bl_decoder_instance_id, bl_decoder_din_port, bl_decoder_din_port_info.pins()[0]);
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Add module nets from the top module to WL decoder's inputs
|
||||||
|
*/
|
||||||
|
ModulePortId wl_decoder_en_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ENABLE_PORT_NAME));
|
||||||
|
BasicPort wl_decoder_en_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_en_port);
|
||||||
|
|
||||||
|
ModulePortId wl_decoder_addr_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
||||||
|
BasicPort wl_decoder_addr_port_info = module_manager.module_port(wl_decoder_module, bl_decoder_addr_port);
|
||||||
|
|
||||||
|
/* Top module Enable port -> WL Decoder Enable port */
|
||||||
|
add_module_bus_nets(module_manager,
|
||||||
|
top_module,
|
||||||
|
top_module, 0, en_port,
|
||||||
|
wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_en_port);
|
||||||
|
|
||||||
|
/* Top module Address port -> WL Decoder Address port */
|
||||||
|
add_module_bus_nets(module_manager,
|
||||||
|
top_module,
|
||||||
|
top_module, 0, wl_addr_port,
|
||||||
|
wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_addr_port);
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Add nets from BL data out to each configurable child
|
||||||
|
*/
|
||||||
|
size_t cur_bl_index = 0;
|
||||||
|
|
||||||
|
ModulePortId bl_decoder_dout_port = module_manager.find_module_port(bl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME));
|
||||||
|
BasicPort bl_decoder_dout_port_info = module_manager.module_port(bl_decoder_module, bl_decoder_dout_port);
|
||||||
|
|
||||||
|
std::map<int, size_t> num_bls_per_tile;
|
||||||
|
std::map<int, size_t> num_wls_per_tile;
|
||||||
|
for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) {
|
||||||
|
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
|
||||||
|
vtr::Point<int> coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id];
|
||||||
|
num_bls_per_tile[coord.x()] = std::max(num_bls_per_tile[coord.x()], find_memory_decoder_data_size(find_module_num_config_bits(module_manager, child_module, circuit_lib, sram_model, CONFIG_MEM_QL_MEMORY_BANK)));
|
||||||
|
num_wls_per_tile[coord.y()] = std::max(num_wls_per_tile[coord.y()], find_memory_decoder_data_size(find_module_num_config_bits(module_manager, child_module, circuit_lib, sram_model, CONFIG_MEM_QL_MEMORY_BANK)));
|
||||||
|
|
||||||
|
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
|
||||||
|
|
||||||
|
/* Find the BL port */
|
||||||
|
ModulePortId child_bl_port = module_manager.find_module_port(child_module, std::string(MEMORY_BL_PORT_NAME));
|
||||||
|
BasicPort child_bl_port_info = module_manager.module_port(child_module, child_bl_port);
|
||||||
|
|
||||||
|
for (const size_t& sink_bl_pin : child_bl_port_info.pins()) {
|
||||||
|
/* Find the BL decoder data index:
|
||||||
|
* It should be the residual when divided by the number of BLs
|
||||||
|
*/
|
||||||
|
size_t bl_pin_id = std::floor(cur_bl_index / num_bls);
|
||||||
|
if (!(bl_pin_id < bl_decoder_dout_port_info.pins().size()))
|
||||||
|
VTR_ASSERT(bl_pin_id < bl_decoder_dout_port_info.pins().size());
|
||||||
|
|
||||||
|
/* Create net */
|
||||||
|
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
|
||||||
|
bl_decoder_module, curr_bl_decoder_instance_id,
|
||||||
|
bl_decoder_dout_port,
|
||||||
|
bl_decoder_dout_port_info.pins()[bl_pin_id]);
|
||||||
|
VTR_ASSERT(ModuleNetId::INVALID() != net);
|
||||||
|
|
||||||
|
/* Add net sink */
|
||||||
|
module_manager.add_module_net_sink(top_module, net,
|
||||||
|
child_module, child_instance, child_bl_port, sink_bl_pin);
|
||||||
|
|
||||||
|
/* Increment the BL index */
|
||||||
|
cur_bl_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Add nets from WL data out to each configurable child
|
||||||
|
*/
|
||||||
|
size_t cur_wl_index = 0;
|
||||||
|
|
||||||
|
ModulePortId wl_decoder_dout_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME));
|
||||||
|
BasicPort wl_decoder_dout_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_dout_port);
|
||||||
|
|
||||||
|
for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) {
|
||||||
|
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
|
||||||
|
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
|
||||||
|
|
||||||
|
/* Find the WL port */
|
||||||
|
ModulePortId child_wl_port = module_manager.find_module_port(child_module, std::string(MEMORY_WL_PORT_NAME));
|
||||||
|
BasicPort child_wl_port_info = module_manager.module_port(child_module, child_wl_port);
|
||||||
|
|
||||||
|
for (const size_t& sink_wl_pin : child_wl_port_info.pins()) {
|
||||||
|
/* Find the BL decoder data index:
|
||||||
|
* It should be the residual when divided by the number of BLs
|
||||||
|
*/
|
||||||
|
size_t wl_pin_id = cur_wl_index % num_wls;
|
||||||
|
|
||||||
|
/* Create net */
|
||||||
|
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
|
||||||
|
wl_decoder_module, curr_wl_decoder_instance_id,
|
||||||
|
wl_decoder_dout_port,
|
||||||
|
wl_decoder_dout_port_info.pins()[wl_pin_id]);
|
||||||
|
VTR_ASSERT(ModuleNetId::INVALID() != net);
|
||||||
|
|
||||||
|
/* Add net sink */
|
||||||
|
module_manager.add_module_net_sink(top_module, net,
|
||||||
|
child_module, child_instance, child_wl_port, sink_wl_pin);
|
||||||
|
|
||||||
|
/* Increment the WL index */
|
||||||
|
cur_wl_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Add the BL and WL decoders to the end of configurable children list
|
||||||
|
* Note: this MUST be done after adding all the module nets to other regular configurable children
|
||||||
|
*/
|
||||||
|
module_manager.add_configurable_child(top_module, bl_decoder_module, curr_bl_decoder_instance_id);
|
||||||
|
module_manager.add_configurable_child_to_region(top_module,
|
||||||
|
config_region,
|
||||||
|
bl_decoder_module,
|
||||||
|
curr_bl_decoder_instance_id,
|
||||||
|
module_manager.configurable_children(top_module).size() - 1);
|
||||||
|
|
||||||
|
module_manager.add_configurable_child(top_module, wl_decoder_module, curr_wl_decoder_instance_id);
|
||||||
|
module_manager.add_configurable_child_to_region(top_module,
|
||||||
|
config_region,
|
||||||
|
wl_decoder_module,
|
||||||
|
curr_wl_decoder_instance_id,
|
||||||
|
module_manager.configurable_children(top_module).size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef BUILD_TOP_MODULE_MEMORY_BANK_H
|
||||||
|
#define BUILD_TOP_MODULE_MEMORY_BANK_H
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Include header files that are required by function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "vtr_vector.h"
|
||||||
|
#include "vtr_ndmatrix.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
#include "circuit_library.h"
|
||||||
|
#include "decoder_library.h"
|
||||||
|
#include "build_top_module_memory_utils.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager,
|
||||||
|
DecoderLibrary& decoder_lib,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
|
const TopModuleNumConfigBits& num_config_bits);
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef BUILD_TOP_MODULE_MEMORY_UTILS_H
|
||||||
|
#define BUILD_TOP_MODULE_MEMORY_UTILS_H
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Include header files that are required by function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "vtr_vector.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/* A data structure to store the number of configuration bits for each configurable region
|
||||||
|
* of the top-level module.
|
||||||
|
* For different configuration protocol, the std::pair<size_t, size_t> represents different data
|
||||||
|
* See details in each function about how the data is organized
|
||||||
|
*/
|
||||||
|
typedef vtr::vector<ConfigRegionId, std::pair<size_t, size_t>> TopModuleNumConfigBits;
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue