[Engine] Adding the function that builds a shift register module for BL/WLs

This commit is contained in:
tangxifan 2021-09-28 22:49:24 -07:00
parent 834bdd2b07
commit 7723e00e6c
5 changed files with 295 additions and 28 deletions

View File

@ -822,6 +822,23 @@ std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix
return blwl_port_prefix + std::string("_config_region_") + std::to_string(size_t(region_id));
}
/*********************************************************************
* Generate the module name for a shift register chain which configures BLs
*********************************************************************/
std::string generate_bl_shift_register_module_name(const std::string& memory_model_name,
const size_t& shift_register_size) {
return std::string("bl_shift_register_") + memory_model_name + std::string("_size") + std::to_string(shift_register_size);
}
/*********************************************************************
* Generate the module name for a shift register chain which configures WLs
*********************************************************************/
std::string generate_wl_shift_register_module_name(const std::string& memory_model_name,
const size_t& shift_register_size) {
return std::string("wl_shift_register_") + memory_model_name + std::string("_size") + std::to_string(shift_register_size);
}
/*********************************************************************
* Generate the port name for the input bus of a routing multiplexer
* This is very useful in Verilog code generation where the inputs of

View File

@ -187,6 +187,12 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix,
const ConfigRegionId& region_id);
std::string generate_bl_shift_register_module_name(const std::string& memory_model_name,
const size_t& shift_register_size);
std::string generate_wl_shift_register_module_name(const std::string& memory_model_name,
const size_t& shift_register_size);
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,

View File

@ -78,7 +78,6 @@ void add_module_input_nets_to_mem_modules(ModuleManager& module_manager,
* pin of output port of the memory module, where W is the size of port
* 3. It assumes fixed port name for output ports
********************************************************************/
static
std::vector<ModuleNetId> add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
const ModuleId& mem_module,
const std::string& mem_module_output_name,
@ -162,7 +161,6 @@ void add_module_output_nets_to_mem_modules(ModuleManager& module_manager,
* Do not use it to replace the
* add_module_nets_cmos_memory_chain_config_bus() !!!
*********************************************************************/
static
void add_module_nets_to_cmos_memory_config_chain_module(ModuleManager& module_manager,
const ModuleId& parent_module,
const CircuitLibrary& circuit_lib,

View File

@ -16,6 +16,22 @@
/* begin namespace openfpga */
namespace openfpga {
std::vector<ModuleNetId> add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
const ModuleId& mem_module,
const std::string& mem_module_output_name,
const CircuitLibrary& circuit_lib,
const CircuitPortId& circuit_port,
const ModuleId& child_module,
const size_t& child_index,
const size_t& child_instance);
void add_module_nets_to_cmos_memory_config_chain_module(ModuleManager& module_manager,
const ModuleId& parent_module,
const CircuitLibrary& circuit_lib,
const CircuitPortId& model_input_port,
const CircuitPortId& model_output_port);
void build_memory_modules(ModuleManager& module_manager,
DecoderLibrary& arch_decoder_lib,
const MuxLibrary& mux_lib,

View File

@ -24,6 +24,7 @@
#include "decoder_library_utils.h"
#include "module_manager_utils.h"
#include "memory_bank_utils.h"
#include "build_memory_modules.h"
#include "build_decoder_modules.h"
#include "build_top_module_memory_bank.h"
@ -44,11 +45,11 @@ namespace openfpga {
*
********************************************************************/
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) {
ModuleId 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<CircuitPortId> sram_input_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_INPUT, true);
@ -102,13 +103,12 @@ void build_bl_shift_register_chain_module(ModuleManager& module_manager,
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];
for (const auto& child_module_output_port : sram_bl_ports) {
std::string chain_output_port_name = std::string(BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME);
std::vector<ModuleNetId> 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);
add_module_output_nets_to_chain_mem_modules(module_manager, mem_module,
chain_output_port_name, circuit_lib,
child_module_output_port,
sram_mem_module, i, sram_mem_instance);
}
}
@ -116,21 +116,121 @@ void build_bl_shift_register_chain_module(ModuleManager& module_manager,
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
/* 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
*/
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_module_global_ports_from_child_modules(module_manager, mem_module);
return mem_module;
}
/*********************************************************************
* WL shift register chain module organization
*
* +-------+ +-------+ +-------+
* chain --->| CCFF |--->| CCFF |--->... --->| CCFF |---->chain
* input&clock | [0] | | [1] | | [N-1] | output
* +-------+ +-------+ +-------+
* | | ... | config-memory output
* v v v
* +-----------------------------------------+
* | WL/WLRs of configurable modules |
*
********************************************************************/
static
ModuleId build_wl_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<CircuitPortId> 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<CircuitPortId> 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 WL ports from the SRAM */
std::vector<CircuitPortId> sram_wl_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WL, true);
VTR_ASSERT(1 == sram_wl_ports.size());
/* Get the optional WLR ports from the SRAM */
std::vector<CircuitPortId> sram_wlr_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR, true);
VTR_ASSERT(0 == sram_wlr_ports.size() || 1 == sram_wlr_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(WL_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(WL_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_wl_port(WL_SHIFT_REGISTER_CHAIN_WL_OUT_NAME,
num_mems);
module_manager.add_port(mem_module, chain_wl_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 wl outputs of sram modules to WL outputs of memory module */
for (const auto& child_module_output_port : sram_wl_ports) {
std::string chain_output_port_name = std::string(WL_SHIFT_REGISTER_CHAIN_WL_OUT_NAME);
add_module_output_nets_to_chain_mem_modules(module_manager, mem_module,
chain_output_port_name, circuit_lib,
child_module_output_port,
sram_mem_module, i, sram_mem_instance);
}
/* Build module nets to wire wlr outputs of sram modules to WLR outputs of memory module */
for (const auto& child_module_output_port : sram_wlr_ports) {
std::string chain_output_port_name = std::string(WL_SHIFT_REGISTER_CHAIN_WLR_OUT_NAME);
add_module_output_nets_to_chain_mem_modules(module_manager, mem_module,
chain_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]);
/* 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);
}
return mem_module;
}
/*********************************************************************
* This function to add nets for quicklogic memory banks
@ -813,14 +913,14 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module
}
/* 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);
//}
for (const size_t& sr_size : unique_sr_sizes) {
std::string sr_module_name = generate_bl_shift_register_module_name(circuit_lib.model_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);
@ -1002,6 +1102,136 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(ModuleManager
}
}
/*********************************************************************
* Top-level function to add nets for quicklogic memory banks using shift registers to control BL/WLs
*
* @note this function only adds the WL configuration bus
*
* @note see detailed explanation on the bus connection in function add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus()
**********************************************************************/
static
void add_top_module_nets_cmos_ql_memory_bank_wl_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 wl_memory_model = config_protocol.wl_memory_model();
/* Find out the unique shift register chain sizes */
std::vector<size_t> 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_wls = compute_memory_bank_regional_num_wls(module_manager, top_module,
config_region,
circuit_lib, sram_model);
unique_sr_sizes.push_back(num_wls);
}
/* TODO: Build submodules for shift register chains */
for (const size_t& sr_size : unique_sr_sizes) {
std::string sr_module_name = generate_wl_shift_register_module_name(circuit_lib.model_name(wl_memory_model), sr_size);
ModuleId sr_bank_module = build_wl_shift_register_chain_module(module_manager,
circuit_lib,
sr_module_name,
wl_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 WLs of top-level module and WLs 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<int, int> child_y_range = compute_memory_bank_regional_configurable_child_y_range(module_manager, top_module, config_region);
std::map<int, size_t> num_wls_per_tile = compute_memory_bank_regional_wordline_numbers_per_tile(module_manager, top_module,
config_region,
circuit_lib, sram_model);
std::map<int, size_t> wl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_y_range, num_wls_per_tile);
/**************************************************************
* Add WL nets from top module to each configurable child
*/
ModulePortId top_module_wl_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region));
BasicPort top_module_wl_port_info = module_manager.module_port(top_module, top_module_wl_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<int> 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 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);
size_t cur_wl_index = 0;
for (const size_t& sink_wl_pin : child_wl_port_info.pins()) {
size_t wl_pin_id = wl_start_index_per_tile[coord.y()] + cur_wl_index;
VTR_ASSERT(wl_pin_id < top_module_wl_port_info.pins().size());
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
top_module, 0,
top_module_wl_port,
top_module_wl_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);
cur_wl_index++;
}
}
/**************************************************************
* Optional: Add WLR nets from top module to each configurable child
*/
ModulePortId top_module_wlr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WLR_PORT_NAME), config_region));
BasicPort top_module_wlr_port_info;
if (top_module_wlr_port) {
top_module_wlr_port_info = module_manager.module_port(top_module, top_module_wlr_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<int> 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 WL port */
ModulePortId child_wlr_port = module_manager.find_module_port(child_module, std::string(MEMORY_WLR_PORT_NAME));
BasicPort child_wlr_port_info = module_manager.module_port(child_module, child_wlr_port);
size_t cur_wlr_index = 0;
for (const size_t& sink_wlr_pin : child_wlr_port_info.pins()) {
size_t wlr_pin_id = wl_start_index_per_tile[coord.y()] + cur_wlr_index;
VTR_ASSERT(wlr_pin_id < top_module_wlr_port_info.pins().size());
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
top_module, 0,
top_module_wlr_port,
top_module_wlr_port_info.pins()[wlr_pin_id]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Add net sink */
module_manager.add_module_net_sink(top_module, net,
child_module, child_instance, child_wlr_port, sink_wlr_pin);
cur_wlr_index++;
}
}
}
}
}
/*********************************************************************
* Top-level function to add nets for quicklogic memory banks
* - Each configuration region has independent memory bank circuitry
@ -1054,7 +1284,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_wl_shift_register_config_bus(module_manager, top_module, circuit_lib, config_protocol);
break;
}
default: {