diff --git a/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h index af151a7a5..4d51a8f12 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h @@ -13,10 +13,18 @@ namespace openfpga { /* Top-level module name */ constexpr char* FPGA_TOP_MODULE_NAME = "fpga_top"; +/* Configuration chain naming constant strings */ constexpr char* CONFIGURABLE_MEMORY_CHAIN_IN_NAME = "ccff_head"; constexpr char* CONFIGURABLE_MEMORY_CHAIN_OUT_NAME = "ccff_tail"; constexpr char* CONFIGURABLE_MEMORY_DATA_OUT_NAME = "mem_out"; constexpr char* CONFIGURABLE_MEMORY_INVERTED_DATA_OUT_NAME = "mem_outb"; +constexpr char* BL_SHIFT_REGISTER_CHAIN_HEAD_NAME = "bl_sr_head"; +constexpr char* BL_SHIFT_REGISTER_CHAIN_TAIL_NAME = "bl_sr_tail"; +constexpr char* BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME = "bl_sr_bl_out"; +constexpr char* WL_SHIFT_REGISTER_CHAIN_HEAD_NAME = "wl_sr_head"; +constexpr char* WL_SHIFT_REGISTER_CHAIN_TAIL_NAME = "wl_sr_tail"; +constexpr char* WL_SHIFT_REGISTER_CHAIN_WL_OUT_NAME = "wl_sr_wl_out"; +constexpr char* WL_SHIFT_REGISTER_CHAIN_WLR_OUT_NAME = "wl_sr_wlr_out"; /* IO PORT */ /* Prefix of global input, output and inout ports of FPGA fabric */ diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index 188efd2f4..d3711ba2a 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -30,6 +30,108 @@ /* begin namespace openfpga */ namespace openfpga { +/********************************************************************* + * BL shift register chain module organization + * + * +-------+ +-------+ +-------+ + * chain --->| CCFF |--->| CCFF |--->... --->| CCFF |---->chain + * input&clock | [0] | | [1] | | [N-1] | output + * +-------+ +-------+ +-------+ + * | | ... | config-memory output + * v v v + * +-----------------------------------------+ + * | BLs of configurable modules | + * + ********************************************************************/ +static +void build_bl_shift_register_chain_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const std::string& module_name, + const CircuitModelId& sram_model, + const size_t& num_mems) { + + /* Get the input ports from the SRAM */ + std::vector sram_input_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_INPUT, true); + VTR_ASSERT(1 == sram_input_ports.size()); + + /* Get the output ports from the SRAM */ + std::vector sram_output_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_OUTPUT, true); + VTR_ASSERT(1 == sram_output_ports.size()); + + /* Get the BL ports from the SRAM */ + std::vector sram_bl_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_BL, true); + VTR_ASSERT(1 == sram_bl_ports.size()); + + /* Create a module and add to the module manager */ + ModuleId mem_module = module_manager.add_module(module_name); + VTR_ASSERT(true == module_manager.valid_module_id(mem_module)); + + /* Label module usage */ + module_manager.set_module_usage(mem_module, ModuleManager::MODULE_CONFIG); + + /* Add an input port, which is the head of configuration chain in the module */ + /* TODO: restriction!!! + * consider only the first input of the CCFF model as the D port, + * which will be connected to the head of the chain + */ + BasicPort chain_head_port(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME, + circuit_lib.port_size(sram_input_ports[0])); + module_manager.add_port(mem_module, chain_head_port, ModuleManager::MODULE_INPUT_PORT); + + /* Add an output port, which is the tail of configuration chain in the module */ + /* TODO: restriction!!! + * consider only the first output of the CCFF model as the Q port, + * which will be connected to the tail of the chain + */ + BasicPort chain_tail_port(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME, + circuit_lib.port_size(sram_output_ports[0])); + module_manager.add_port(mem_module, chain_tail_port, ModuleManager::MODULE_OUTPUT_PORT); + + /* Add the output ports to output BL signals */ + BasicPort chain_bl_port(BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME, + num_mems); + module_manager.add_port(mem_module, chain_bl_port, ModuleManager::MODULE_OUTPUT_PORT); + + /* Find the sram module in the module manager */ + ModuleId sram_mem_module = module_manager.find_module(circuit_lib.model_name(sram_model)); + + /* Instanciate each submodule */ + for (size_t i = 0; i < num_mems; ++i) { + size_t sram_mem_instance = module_manager.num_instance(mem_module, sram_mem_module); + module_manager.add_child_module(mem_module, sram_mem_module); + module_manager.add_configurable_child(mem_module, sram_mem_module, sram_mem_instance); + + /* Build module nets to wire bl outputs of sram modules to BL outputs of memory module */ + for (size_t iport = 0; iport < num_bl_ports; ++iport) { + CircuitPortId child_module_output_port = sram_bl_ports[iport]; + std::string chain_output_port_name = std::string(BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME); + std::vector output_nets = add_module_output_nets_to_chain_mem_modules(module_manager, mem_module, + chan_output_port_name, circuit_lib, + child_module_output_port, + sram_mem_module, i, sram_mem_instance); + } + } + + /* Build module nets to wire the configuration chain */ + add_module_nets_to_cmos_memory_config_chain_module(module_manager, mem_module, + circuit_lib, sram_input_ports[0], sram_output_ports[0]); + + /* If there is a second input defined, + * add nets to short wire the 2nd inputs to the first inputs + */ + if (2 == sram_input_ports.size()) { + add_module_nets_to_cmos_memory_scan_chain_module(module_manager, mem_module, + circuit_lib, sram_input_ports[1], sram_output_ports[0]); + } + + /* Add global ports to the pb_module: + * This is a much easier job after adding sub modules (instances), + * we just need to find all the global ports from the child modules and build a list of it + */ + add_module_global_ports_from_child_modules(module_manager, mem_module); +} + + /********************************************************************* * This function to add nets for quicklogic memory banks * Each configuration region has independent memory bank circuitry @@ -640,6 +742,161 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus(ModuleManager } } +/********************************************************************* + * This function to add nets for quicklogic memory banks using shift registers to manipulate BL/WLs + * Each configuration region has independent BL/WL shift register banks + * - Find the number of BLs and WLs required for each region + * - Find the number of BL and WL shift register chains required for each region + * - Create the module of shift register chain for each unique size + * - Create nets to connect from top-level module inputs to BL/WL shift register chains + * - Create nets to connect from BL/WL shift register chains to BL/WL of configurable children + * + * @note this function only adds the BL protocol + * + * Detailed schematic of each memory bank: + * @note The numbers are just made to show a simplified example, practical cases are more complicated! + * + * sr_clk sr_head sr_tail + * | | ^ + * v v | + * +-------------------------------------------------+ + * | Bit Line shift register chains | + * +-------------------------------------------------+ + * | | | + * +---------+ BL[0:9] BL[10:17] BL[18:22] + * | | | | | + * | | | | | + * | Word |--WL[0:3]-->-----------+---------------+---- ... |------+--> + * | | | | | | | | + * | Line | | v | v | v + * | | | +-------+ | +-------+ | +------+ + * | shift | +-->| SRAM | +-->| SRAM | +->| SRAM | + * | | | | [0:8] | | | [0:5] | ... | | [0:7]| + * | register| | +-------+ | +-------+ | +------+ + * | | | | | + * | chains |--WL[4:14] -----------+--------------+--------- | -----+--> + * | | | | | | | | + * | | | v | v | v + * | | | +-------+ | +-------+ | +-------+ + * | | +-->| SRAM | | | SRAM | +->| SRAM | + * | | | | [0:80]| | | [0:63]| ... | | [0:31]| + * | | | +-------+ | +-------+ | +-------+ + * | | | | + * | | | ... ... ... | ... + * | | | | | + * | |--WL[15:18] -----------+---------------+---- --- | -----+--> + * | | | | | | | | + * | | | v | v | v + * +---------+ | +-------+ | +-------+ | +-------+ + * +-->| SRAM | +-->| SRAM | +->| SRAM | + * | |[0:5] | | | [0:8] | ... | | [0:2] | + * | +-------+ | +-------+ | +-------+ + * v v v + * WL[0:9] WL[0:7] WL[0:4] + * + **********************************************************************/ +static +void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const ConfigProtocol& config_protocol) { + CircuitModelId sram_model = config_protocol.memory_model(); + CircuitModelId bl_memory_model = config_protocol.bl_memory_model(); + /* Find out the unique shift register chain sizes */ + std::vector unique_sr_sizes; + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + /* TODO: Need to find how to cut the BLs when there are multiple banks for shift registers in a region */ + size_t num_bls = compute_memory_bank_regional_num_bls(module_manager, top_module, + config_region, + circuit_lib, sram_model); + unique_sr_sizes.push_back(num_bls); + } + + /* TODO: Build submodules for shift register chains */ + //for (const size_t& sr_size : unique_sr_sizes) { + // std::string sr_module_name = generate_bl_shift_register_module_name(bl_memory_model, sr_size); + // ModuleId sr_bank_module = build_bl_shift_register_chain_module(module_manager, + // circuit_lib, + // sr_module_name, + // bl_memory_model, + // sr_size); + //} + + /* TODO: Instanciate the shift register chains in the top-level module */ + //module_manager.add_child_module(top_module, sr_bank_module); + + /* TODO: create connections between top-level module and the BL shift register banks */ + + /* Create connections between BLs of top-level module and BLs of child modules for each region */ + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + /************************************************************** + * Precompute the BLs and WLs distribution across the FPGA fabric + * The distribution is a matrix which contains the starting index of BL/WL for each column or row + */ + std::pair child_x_range = compute_memory_bank_regional_configurable_child_x_range(module_manager, top_module, config_region); + std::map num_bls_per_tile = compute_memory_bank_regional_bitline_numbers_per_tile(module_manager, top_module, + config_region, + circuit_lib, sram_model); + std::map bl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_x_range, num_bls_per_tile); + + /************************************************************** + * Add BL nets from top module to each configurable child + * BL pins of top module are connected to the BL input pins of each PB/CB/SB + * For all the PB/CB/SB in the same column, they share the same set of BLs + * A quick example + * + * BL[i .. i + sqrt(N)] + * | + * | CLB[1][H] + * | +---------+ + * | | SRAM | + * +-->| [0..N] | + * | +---------+ + * | + * ... + * | CLB[1][1] + * | +---------+ + * | | SRAM | + * +-->| [0..N] | + * | +---------+ + * | + */ + ModulePortId top_module_bl_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region)); + BasicPort top_module_bl_port_info = module_manager.module_port(top_module, top_module_bl_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]; + vtr::Point coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; + + 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); + + size_t cur_bl_index = 0; + + for (const size_t& sink_bl_pin : child_bl_port_info.pins()) { + size_t bl_pin_id = bl_start_index_per_tile[coord.x()] + cur_bl_index; + VTR_ASSERT(bl_pin_id < top_module_bl_port_info.pins().size()); + + /* Create net */ + ModuleNetId net = create_module_source_pin_net(module_manager, top_module, + top_module, 0, + top_module_bl_port, + top_module_bl_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); + + cur_bl_index++; + } + } + } +} + /********************************************************************* * Top-level function to add nets for quicklogic memory banks using flatten BL/WLs * Each configuration region has independent BL/WLs @@ -778,7 +1035,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { - /* TODO */ + add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(module_manager, top_module, circuit_lib, config_protocol); break; } default: { @@ -872,7 +1129,14 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { - /* TODO */ + /* Each region will have independent shift register banks */ + for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { + size_t num_heads = config_protocol.bl_num_banks(); + BasicPort blsr_head_port(generate_regional_blwl_port_name(std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME), config_region), num_heads); + module_manager.add_port(module_id, blsr_head_port, ModuleManager::MODULE_INPUT_PORT); + BasicPort blsr_tail_port(generate_regional_blwl_port_name(std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME), config_region), num_heads); + module_manager.add_port(module_id, blsr_tail_port, ModuleManager::MODULE_INPUT_PORT); + } break; } default: { @@ -914,7 +1178,14 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { - /* TODO */ + /* Each region will have independent shift register banks */ + for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { + size_t num_heads = config_protocol.wl_num_banks(); + BasicPort wlsr_head_port(generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME), config_region), num_heads); + module_manager.add_port(module_id, wlsr_head_port, ModuleManager::MODULE_INPUT_PORT); + BasicPort wlsr_tail_port(generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME), config_region), num_heads); + module_manager.add_port(module_id, wlsr_tail_port, ModuleManager::MODULE_INPUT_PORT); + } break; } default: { diff --git a/openfpga/src/utils/memory_bank_utils.cpp b/openfpga/src/utils/memory_bank_utils.cpp index 66eb938f3..dcb224fc6 100644 --- a/openfpga/src/utils/memory_bank_utils.cpp +++ b/openfpga/src/utils/memory_bank_utils.cpp @@ -84,6 +84,22 @@ size_t find_module_ql_memory_bank_num_blwls(const ModuleManager& module_manager, return num_blwls; } +size_t compute_memory_bank_regional_num_bls(const ModuleManager& module_manager, + const ModuleId& top_module, + const ConfigRegionId& config_region, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model) { + size_t num_bls = 0; + + 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 coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; + num_bls += find_module_ql_memory_bank_num_blwls(module_manager, child_module, circuit_lib, sram_model, CONFIG_MEM_QL_MEMORY_BANK, CIRCUIT_MODEL_PORT_BL); + } + + return num_bls; +} + std::map compute_memory_bank_regional_bitline_numbers_per_tile(const ModuleManager& module_manager, const ModuleId& top_module, const ConfigRegionId& config_region, @@ -100,6 +116,22 @@ std::map compute_memory_bank_regional_bitline_numbers_per_tile(cons return num_bls_per_tile; } +size_t compute_memory_bank_regional_num_wls(const ModuleManager& module_manager, + const ModuleId& top_module, + const ConfigRegionId& config_region, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model) { + size_t num_wls = 0; + + 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 coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; + num_wls += find_module_ql_memory_bank_num_blwls(module_manager, child_module, circuit_lib, sram_model, CONFIG_MEM_QL_MEMORY_BANK, CIRCUIT_MODEL_PORT_WL); + } + + return num_wls; +} + std::map compute_memory_bank_regional_wordline_numbers_per_tile(const ModuleManager& module_manager, const ModuleId& top_module, const ConfigRegionId& config_region, diff --git a/openfpga/src/utils/memory_bank_utils.h b/openfpga/src/utils/memory_bank_utils.h index 237098927..730d19271 100644 --- a/openfpga/src/utils/memory_bank_utils.h +++ b/openfpga/src/utils/memory_bank_utils.h @@ -48,6 +48,14 @@ size_t find_module_ql_memory_bank_num_blwls(const ModuleManager& module_manager, const CircuitModelId& sram_model, const e_config_protocol_type& sram_orgz_type, const e_circuit_model_port_type& circuit_port_type); +/** + * @brief Precompute the total number of bit lines required by a specific configuration region + */ +size_t compute_memory_bank_regional_num_bls(const ModuleManager& module_manager, + const ModuleId& top_module, + const ConfigRegionId& config_region, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model); /** * @brief Precompute the number of bit lines required by each tile under a specific configuration region @@ -60,6 +68,15 @@ std::map compute_memory_bank_regional_bitline_numbers_per_tile(cons const ConfigRegionId& config_region, const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model); +/** + * @brief Precompute the total number of word lines required by a specific configuration region + */ +size_t compute_memory_bank_regional_num_wls(const ModuleManager& module_manager, + const ModuleId& top_module, + const ConfigRegionId& config_region, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model); + /** * @brief Precompute the number of word lines required by each tile under a specific configuration region * @note