diff --git a/openfpga/src/base/openfpga_reserved_words.h b/openfpga/src/base/openfpga_reserved_words.h index 40a2af96b..a9b31f64e 100644 --- a/openfpga/src/base/openfpga_reserved_words.h +++ b/openfpga/src/base/openfpga_reserved_words.h @@ -38,6 +38,8 @@ constexpr char* DECODER_ADDRESS_PORT_NAME = "address"; constexpr char* DECODER_DATA_IN_PORT_NAME = "data_in"; constexpr char* DECODER_DATA_OUT_PORT_NAME = "data_out"; constexpr char* DECODER_DATA_OUT_INV_PORT_NAME = "data_out_inv"; +constexpr char* DECODER_BL_ADDRESS_PORT_NAME = "bl_address"; +constexpr char* DECODER_WL_ADDRESS_PORT_NAME = "wl_address"; /* Inverted port naming */ constexpr char* INV_PORT_POSTFIX = "_inv"; diff --git a/openfpga/src/fabric/build_top_module.cpp b/openfpga/src/fabric/build_top_module.cpp index 072548807..7b05a5676 100644 --- a/openfpga/src/fabric/build_top_module.cpp +++ b/openfpga/src/fabric/build_top_module.cpp @@ -384,7 +384,9 @@ void build_top_module(ModuleManager& module_manager, */ size_t module_num_config_bits = find_module_num_config_bits_from_child_modules(module_manager, top_module, circuit_lib, sram_model, sram_orgz_type); if (0 < module_num_config_bits) { - add_sram_ports_to_module_manager(module_manager, top_module, circuit_lib, sram_model, sram_orgz_type, module_num_config_bits); + add_top_module_sram_ports(module_manager, top_module, + circuit_lib, sram_model, + sram_orgz_type, module_num_config_bits); } /* Add module nets to connect memory cells inside diff --git a/openfpga/src/fabric/build_top_module_memory.cpp b/openfpga/src/fabric/build_top_module_memory.cpp index b5d7f1db1..c2a726ea9 100644 --- a/openfpga/src/fabric/build_top_module_memory.cpp +++ b/openfpga/src/fabric/build_top_module_memory.cpp @@ -13,6 +13,8 @@ #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_top_module_memory.h" @@ -361,6 +363,104 @@ void organize_top_module_memory_modules(ModuleManager& module_manager, } } +/******************************************************************** + * Add a list of ports that are used for SRAM configuration to the FPGA + * top-level module + * 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: + * - An enable signal + * - A BL address port + * - A WL address port + * - A data-in port for the BL decoder + * 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_top_module_sram_ports(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 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_STANDALONE: { + 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_MEMORY_BANK: { + BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1); + module_manager.add_port(module_id, en_port, ModuleManager::MODULE_INPUT_PORT); + + size_t bl_addr_size = find_memory_decoder_addr_size(num_config_bits); + 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); + + size_t wl_addr_size = find_memory_decoder_addr_size(num_config_bits); + 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); + + BasicPort din_port(std::string(DECODER_DATA_IN_PORT_NAME), 1); + module_manager.add_port(module_id, din_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 the port-to-port connection between all the memory modules diff --git a/openfpga/src/fabric/build_top_module_memory.h b/openfpga/src/fabric/build_top_module_memory.h index 1d0295b87..a912845b2 100644 --- a/openfpga/src/fabric/build_top_module_memory.h +++ b/openfpga/src/fabric/build_top_module_memory.h @@ -34,6 +34,13 @@ void organize_top_module_memory_modules(ModuleManager& module_manager, const std::map>& cb_instance_ids, const bool& compact_routing_hierarchy); +void add_top_module_sram_ports(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); + void add_top_module_nets_memory_config_bus(ModuleManager& module_manager, DecoderLibrary& decoder_lib, const ModuleId& parent_module, diff --git a/openfpga/src/utils/decoder_library_utils.cpp b/openfpga/src/utils/decoder_library_utils.cpp index a41e439ef..20f7473b2 100644 --- a/openfpga/src/utils/decoder_library_utils.cpp +++ b/openfpga/src/utils/decoder_library_utils.cpp @@ -38,6 +38,45 @@ size_t find_mux_local_decoder_addr_size(const size_t& data_size) { return ceil(log(data_size) / log(2)); } +/*************************************************************************************** + * Find the size of address lines for a memory decoder to access a memory array + * Addr lines + * | | ... | + * v v v + * +-----------+ + * / Local \ + * / Decoder \ + * +-----------------+ + * | | | ... | | | + * v v v v v v + * Data outputs + * + * +------+ +------+ +------+ + * | SRAM | | SRAM | ... | SRAM | + * | [0] | | [1] | | [i] | + * +------+ +------+ +------+ + * + * +------+ +------+ +------+ + * | SRAM | | SRAM | ... | SRAM | + * | [i+1]| | [i+2]| |[2i-1]| + * +------+ +------+ +------+ + * + * ... ... ... + * + * +------+ +------+ +------+ + * | SRAM | | SRAM | ... | SRAM | + * | [x] | | [x+1]| | [N] | + * +------+ +------+ +------+ + * + * Due to the shared lines in the array, + * each memory decoder (BL or WL) will access sqrt(N) control lins (BL or WL) + * Then we can use the function for mux local encoder to compute the address size + * + ***************************************************************************************/ +size_t find_memory_decoder_addr_size(const size_t& num_mems) { + return find_mux_local_decoder_addr_size((size_t)std::ceil(std::sqrt((float)num_mems))); +} + /*************************************************************************************** * Try to find if the decoder already exists in the library, * If there is no such decoder, add it to the library diff --git a/openfpga/src/utils/decoder_library_utils.h b/openfpga/src/utils/decoder_library_utils.h index d55a0750a..e43068f5f 100644 --- a/openfpga/src/utils/decoder_library_utils.h +++ b/openfpga/src/utils/decoder_library_utils.h @@ -13,6 +13,8 @@ bool need_mux_local_decoder(const size_t& data_size); size_t find_mux_local_decoder_addr_size(const size_t& data_size); +size_t find_memory_decoder_addr_size(const size_t& num_mems); + DecoderId add_mux_local_decoder_to_library(DecoderLibrary& decoder_lib, const size_t data_size); diff --git a/openfpga/src/utils/module_manager_utils.cpp b/openfpga/src/utils/module_manager_utils.cpp index cf9808466..ec871368a 100644 --- a/openfpga/src/utils/module_manager_utils.cpp +++ b/openfpga/src/utils/module_manager_utils.cpp @@ -163,7 +163,7 @@ void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_ * The type and names of added ports strongly depend on the * organization of SRAMs. * 1. Standalone SRAMs: - * two ports will be added, which are regular output and inverted output + * 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