[Tool] Many bug fix in the multi-region support for both memory banks and framed-based. Still have problems in multi-region framed-based verification
This commit is contained in:
parent
4c14428400
commit
5bcd559851
|
@ -1349,6 +1349,7 @@ void add_top_module_nets_cmos_memory_frame_short_config_bus(ModuleManager& modul
|
|||
* what is required for this configuration region.
|
||||
* A decoder will be created anyway to avoid address collision
|
||||
* to other configuration regions
|
||||
* The address lines will be aligned from the MSB of top-level address lines!!!
|
||||
* - 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
|
||||
|
@ -1387,14 +1388,12 @@ void add_top_module_nets_cmos_memory_frame_short_config_bus(ModuleManager& modul
|
|||
* | | | |
|
||||
* | +-------------+--------------------+
|
||||
* | |
|
||||
* | ADDR[X - log(N)/log2 - 1: 0]
|
||||
* | ADDR[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_top_module_nets_cmos_memory_frame_decoder_config_bus(ModuleManager& module_manager,
|
||||
|
@ -1404,20 +1403,14 @@ void add_top_module_nets_cmos_memory_frame_decoder_config_bus(ModuleManager& mod
|
|||
std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(parent_module, config_region);
|
||||
std::vector<size_t> configurable_child_instances = module_manager.region_configurable_child_instances(parent_module, config_region);
|
||||
|
||||
ModulePortId parent_addr_port = module_manager.find_module_port(parent_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
||||
BasicPort parent_addr_port_info = module_manager.module_port(parent_module, parent_addr_port);
|
||||
|
||||
/* 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();
|
||||
|
||||
/* Find the number of address bits that are wired directly to configurable children */
|
||||
size_t max_child_addr_size = 0;
|
||||
for (size_t mem_index = 0; mem_index < configurable_children.size(); ++mem_index) {
|
||||
ModuleId child_module = configurable_children[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);
|
||||
max_child_addr_size = std::max(max_child_addr_size, child_addr_port_info.get_width());
|
||||
}
|
||||
|
||||
/* Search the decoder library and try to find one
|
||||
* If not found, create a new module and add it to the module manager
|
||||
*/
|
||||
|
@ -1453,23 +1446,21 @@ void add_top_module_nets_cmos_memory_frame_decoder_config_bus(ModuleManager& mod
|
|||
/* 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) {
|
||||
/* Create a net for the addr pin */
|
||||
ModuleNetId addr_net = create_module_source_pin_net(module_manager, parent_module,
|
||||
parent_module, 0,
|
||||
parent_addr_port,
|
||||
parent_addr_port_info.pins()[ipin + max_child_addr_size]);
|
||||
parent_addr_port_info.pins()[parent_addr_port_info.get_width() - 1 - ipin]);
|
||||
VTR_ASSERT(ModuleNetId::INVALID() != addr_net);
|
||||
|
||||
/* Configure the net sink */
|
||||
module_manager.add_module_net_sink(parent_module, addr_net,
|
||||
decoder_module, decoder_instance,
|
||||
decoder_addr_port,
|
||||
decoder_addr_port_info.pins()[ipin]);
|
||||
decoder_addr_port_info.pins()[decoder_addr_port_info.get_width() - 1 - ipin]);
|
||||
}
|
||||
|
||||
/* Connect the address port of the parent module to the address port of configurable children
|
||||
|
@ -1577,10 +1568,9 @@ void add_top_module_nets_cmos_memory_frame_config_bus(ModuleManager& module_mana
|
|||
const ModuleId& top_module,
|
||||
const vtr::vector<ConfigRegionId, size_t>& num_config_bits) {
|
||||
/* Find the number of address bits for the top-level module */
|
||||
size_t top_addr_size = 0;
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
top_addr_size = std::max(top_addr_size, num_config_bits[config_region]);
|
||||
}
|
||||
ModulePortId top_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
||||
BasicPort top_addr_port_info = module_manager.module_port(top_module, top_addr_port);
|
||||
size_t top_addr_size = top_addr_port_info.get_width();
|
||||
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
if (0 == module_manager.region_configurable_children(top_module, config_region).size()) {
|
||||
|
|
|
@ -325,21 +325,26 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
|
|||
if (1 == num_configurable_children) {
|
||||
add_addr_code = false;
|
||||
} else {
|
||||
/* For more than 2 children, there is a decoder in the tail of the list
|
||||
* We will not decode that, but will access the address size from that module
|
||||
* So, we reduce the number of children by 1
|
||||
*/
|
||||
/* For more than 2 children, there is a decoder in the tail of the list
|
||||
* We will not decode that, but will access the address size from that module
|
||||
* So, we reduce the number of children by 1
|
||||
*/
|
||||
VTR_ASSERT(2 < num_configurable_children);
|
||||
num_configurable_children--;
|
||||
decoder_module = configurable_children.back();
|
||||
|
||||
/* The address code size is the max. of address port of all the configurable children */
|
||||
for (size_t child_id = 0; child_id < num_configurable_children; ++child_id) {
|
||||
ModuleId child_module = configurable_children[child_id];
|
||||
/* The max address code size is the max address code size of all the
|
||||
* configurable children in all the regions
|
||||
*/
|
||||
for (const ModuleId& child_module : module_manager.configurable_children(parent_module)) {
|
||||
/* Bypass any decoder module (which no configurable children */
|
||||
if (module_manager.configurable_children(child_module).empty()) {
|
||||
continue;
|
||||
}
|
||||
const ModulePortId& child_addr_port_id = module_manager.find_module_port(child_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
||||
const BasicPort& child_addr_port = module_manager.module_port(child_module, child_addr_port_id);
|
||||
max_child_addr_code_size = std::max((int)child_addr_port.get_width(), (int)max_child_addr_code_size);
|
||||
}
|
||||
max_child_addr_code_size = std::max(child_addr_port.get_width(), max_child_addr_code_size);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t child_id = 0; child_id < num_configurable_children; ++child_id) {
|
||||
|
@ -369,7 +374,15 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
|
|||
const BasicPort& decoder_addr_port = module_manager.module_port(decoder_module, decoder_addr_port_id);
|
||||
std::vector<char> addr_bits_vec = itobin_charvec(child_id, decoder_addr_port.get_width());
|
||||
|
||||
child_addr_code.insert(child_addr_code.begin(), addr_bits_vec.begin(), addr_bits_vec.end());
|
||||
/* For top-level module, the child address should be added to the tail
|
||||
* For other modules, the child address should be added to the head
|
||||
*/
|
||||
if (top_module == parent_module) {
|
||||
child_addr_code.insert(child_addr_code.end(), addr_bits_vec.begin(), addr_bits_vec.end());
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(top_module != parent_module);
|
||||
child_addr_code.insert(child_addr_code.begin(), addr_bits_vec.begin(), addr_bits_vec.end());
|
||||
}
|
||||
|
||||
/* Note that the address port size of the child module may be smaller than the maximum
|
||||
* of other child modules at this level.
|
||||
|
@ -382,8 +395,8 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
|
|||
* we should add dummy '0' to fill the gap
|
||||
*
|
||||
* Addr_code for child[0]: '000' + addr_bits_vec
|
||||
* Addr_code for child[1]: '0' + addr_bits_vec
|
||||
* Addr_code for child[2]: addr_bits_vec
|
||||
* Addr_code for child[1]: '00' + addr_bits_vec
|
||||
* Addr_code for child[2]: '0' + addr_bits_vec
|
||||
*
|
||||
* Addr[6:8]
|
||||
* |
|
||||
|
@ -392,7 +405,7 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
|
|||
* | Decoder Module |
|
||||
* +-------------------------------------------+
|
||||
*
|
||||
* Addr[0:2] Addr[0:4] Addr[0:5]
|
||||
* Addr[0:2] Addr[0:3] Addr[0:4]
|
||||
* | | |
|
||||
* v v v
|
||||
* +-----------+ +-------------+ +------------+
|
||||
|
@ -570,10 +583,49 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
||||
fabric_bitstream.set_address_length(addr_port_info.get_width());
|
||||
|
||||
/* TODO: Currently only support 1 region. Will expand later! */
|
||||
VTR_ASSERT(1 == module_manager.regions(top_module).size());
|
||||
/* Find the maximum decoder address among all the configurable regions */
|
||||
size_t max_decoder_addr_size = 0;
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(top_module, config_region);
|
||||
/* Bypass the regions that have no decoders */
|
||||
if ( (0 == configurable_children.size())
|
||||
|| (1 == configurable_children.size())) {
|
||||
continue;
|
||||
}
|
||||
ModuleId decoder_module = configurable_children.back();
|
||||
ModulePortId decoder_addr_port_id = module_manager.find_module_port(decoder_module, DECODER_ADDRESS_PORT_NAME);
|
||||
BasicPort decoder_addr_port = module_manager.module_port(decoder_module, decoder_addr_port_id);
|
||||
max_decoder_addr_size = std::max(max_decoder_addr_size, decoder_addr_port.get_width());
|
||||
}
|
||||
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(top_module, config_region);
|
||||
|
||||
/* Bypass non-configurable regions */
|
||||
if (0 == configurable_children.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find the idle address bit which should be added to the head of the address bit
|
||||
* This depends on the number of address bits required by this region
|
||||
* For example:
|
||||
* Top-level address is addr[0:4]
|
||||
* There are 4 decoders in the top-level module, whose address sizes are
|
||||
* decoder A: addr[0:4]
|
||||
* decoder B: addr[0:3]
|
||||
* decoder C: addr[0:2]
|
||||
* decoder D: addr[0:3]
|
||||
* For decoder A, the address fit well
|
||||
* For decoder B, an idle bit should be added '0' + addr[0:3]
|
||||
* For decoder C, two idle bits should be added '00' + addr[0:2]
|
||||
* For decoder D, an idle bit should be added '0' + addr[0:3]
|
||||
*/
|
||||
ModuleId decoder_module = configurable_children.back();
|
||||
ModulePortId decoder_addr_port_id = module_manager.find_module_port(decoder_module, DECODER_ADDRESS_PORT_NAME);
|
||||
BasicPort decoder_addr_port = module_manager.module_port(decoder_module, decoder_addr_port_id);
|
||||
VTR_ASSERT(max_decoder_addr_size >= decoder_addr_port.get_width());
|
||||
std::vector<char> idle_addr_bits(max_decoder_addr_size - decoder_addr_port.get_width(), '0');
|
||||
|
||||
FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region();
|
||||
rec_build_module_fabric_dependent_frame_bitstream(bitstream_manager,
|
||||
std::vector<ConfigBlockId>(1, top_block),
|
||||
|
@ -581,7 +633,7 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
top_module,
|
||||
config_region,
|
||||
std::vector<ModuleId>(1, top_module),
|
||||
std::vector<char>(),
|
||||
idle_addr_bits,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
|
|
|
@ -699,17 +699,24 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
|
|||
100. * ((float)num_config_clock_cycles / (float)(1 + regional_bitstream_max_size) - 1.));
|
||||
}
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
case CONFIG_MEM_FRAME_BASED: {
|
||||
case CONFIG_MEM_MEMORY_BANK: {
|
||||
/* For fast configuration, we will skip all the zero data points */
|
||||
num_config_clock_cycles = 1 + build_memory_bank_fabric_bitstream_by_address(fabric_bitstream).size();
|
||||
if (true == fast_configuration) {
|
||||
size_t full_num_config_clock_cycles = num_config_clock_cycles;
|
||||
num_config_clock_cycles = 1;
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
|
||||
if (bit_value_to_skip != fabric_bitstream.bit_din(bit_id)) {
|
||||
num_config_clock_cycles++;
|
||||
}
|
||||
}
|
||||
num_config_clock_cycles = 1 + find_memory_bank_fast_configuration_fabric_bitstream_size(fabric_bitstream, bit_value_to_skip);
|
||||
VTR_LOG("Fast configuration reduces number of configuration clock cycles from %lu to %lu (compression_rate = %f%)\n",
|
||||
full_num_config_clock_cycles,
|
||||
num_config_clock_cycles,
|
||||
100. * ((float)num_config_clock_cycles / (float)full_num_config_clock_cycles - 1.));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_FRAME_BASED: {
|
||||
num_config_clock_cycles = 1 + build_frame_based_fabric_bitstream_by_address(fabric_bitstream).size();
|
||||
if (true == fast_configuration) {
|
||||
size_t full_num_config_clock_cycles = num_config_clock_cycles;
|
||||
num_config_clock_cycles = 1 + find_frame_based_fast_configuration_fabric_bitstream_size(fabric_bitstream, bit_value_to_skip);
|
||||
VTR_LOG("Fast configuration reduces number of configuration clock cycles from %lu to %lu (compression_rate = %f%)\n",
|
||||
full_num_config_clock_cycles,
|
||||
num_config_clock_cycles,
|
||||
|
@ -1529,46 +1536,8 @@ void print_verilog_top_testbench_memory_bank_bitstream(std::fstream& fp,
|
|||
|
||||
fp << std::endl;
|
||||
|
||||
/* Reorganize the fabric bitstream by the same address across regions:
|
||||
* This is due to that the length of fabric bitstream could be different in each region.
|
||||
* Template:
|
||||
* <bl_address> <wl_address> <din_values_from_different_regions>
|
||||
* An example:
|
||||
* 000000 00000 1011
|
||||
*
|
||||
* Note: the std::map may cause large memory footprint for large bitstream databases!
|
||||
*/
|
||||
std::map<std::pair<std::string, std::string>, std::vector<bool>> fabric_bits_by_addr;
|
||||
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) {
|
||||
/* Create string for BL address */
|
||||
VTR_ASSERT(bl_addr_port.get_width() == fabric_bitstream.bit_bl_address(bit_id).size());
|
||||
std::string bl_addr_str;
|
||||
for (const char& addr_bit : fabric_bitstream.bit_bl_address(bit_id)) {
|
||||
bl_addr_str.push_back(addr_bit);
|
||||
}
|
||||
|
||||
/* Create string for WL address */
|
||||
VTR_ASSERT(wl_addr_port.get_width() == fabric_bitstream.bit_wl_address(bit_id).size());
|
||||
std::string wl_addr_str;
|
||||
for (const char& addr_bit : fabric_bitstream.bit_wl_address(bit_id)) {
|
||||
wl_addr_str.push_back(addr_bit);
|
||||
}
|
||||
|
||||
/* Place the config bit */
|
||||
auto result = fabric_bits_by_addr.find(std::make_pair(bl_addr_str, wl_addr_str));
|
||||
if (result == fabric_bits_by_addr.end()) {
|
||||
/* This is a new bit, resize the vector to the number of regions
|
||||
* and deposit '0' to all the bits
|
||||
*/
|
||||
fabric_bits_by_addr[std::make_pair(bl_addr_str, wl_addr_str)] = std::vector<bool>(fabric_bitstream.regions().size(), false);
|
||||
fabric_bits_by_addr[std::make_pair(bl_addr_str, wl_addr_str)][size_t(region)] = fabric_bitstream.bit_din(bit_id);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(result != fabric_bits_by_addr.end());
|
||||
result->second[size_t(region)] = fabric_bitstream.bit_din(bit_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Reorganize the fabric bitstream by the same address across regions */
|
||||
std::map<std::pair<std::string, std::string>, std::vector<bool>> fabric_bits_by_addr = build_memory_bank_fabric_bitstream_by_address(fabric_bitstream);
|
||||
|
||||
for (const auto& addr_din_pair : fabric_bits_by_addr) {
|
||||
/* When fast configuration is enabled,
|
||||
|
@ -1676,39 +1645,8 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
|
|||
|
||||
fp << std::endl;
|
||||
|
||||
/* Reorganize the fabric bitstream by the same address across regions:
|
||||
* This is due to that the length of fabric bitstream could be different in each region.
|
||||
* Template:
|
||||
* <address> <din_values_from_different_regions>
|
||||
* An example:
|
||||
* 000000 1011
|
||||
*
|
||||
* Note: the std::map may cause large memory footprint for large bitstream databases!
|
||||
*/
|
||||
std::map<std::string, std::vector<bool>> fabric_bits_by_addr;
|
||||
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) {
|
||||
/* Create string for address */
|
||||
VTR_ASSERT(addr_port.get_width() == fabric_bitstream.bit_address(bit_id).size());
|
||||
std::string addr_str;
|
||||
for (const char& addr_bit : fabric_bitstream.bit_address(bit_id)) {
|
||||
addr_str.push_back(addr_bit);
|
||||
}
|
||||
|
||||
/* Place the config bit */
|
||||
auto result = fabric_bits_by_addr.find(addr_str);
|
||||
if (result == fabric_bits_by_addr.end()) {
|
||||
/* This is a new bit, resize the vector to the number of regions
|
||||
* and deposit '0' to all the bits
|
||||
*/
|
||||
fabric_bits_by_addr[addr_str] = std::vector<bool>(fabric_bitstream.regions().size(), false);
|
||||
fabric_bits_by_addr[addr_str][size_t(region)] = fabric_bitstream.bit_din(bit_id);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(result != fabric_bits_by_addr.end());
|
||||
result->second[size_t(region)] = fabric_bitstream.bit_din(bit_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Reorganize the fabric bitstream by the same address across regions */
|
||||
std::map<std::string, std::vector<bool>> fabric_bits_by_addr = build_frame_based_fabric_bitstream_by_address(fabric_bitstream);
|
||||
|
||||
for (const auto& addr_din_pair : fabric_bits_by_addr) {
|
||||
/* When fast configuration is enabled,
|
||||
|
@ -1735,7 +1673,7 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
|
|||
VTR_ASSERT(addr_port.get_width() == addr_din_pair.first.size());
|
||||
fp << addr_din_pair.first;
|
||||
fp << ", ";
|
||||
fp <<"1'b";
|
||||
fp << din_port.get_width() << "'b";
|
||||
VTR_ASSERT(din_port.get_width() == addr_din_pair.second.size());
|
||||
for (const bool& din_value : addr_din_pair.second) {
|
||||
if (true == din_value) {
|
||||
|
@ -1748,7 +1686,7 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
|
|||
fp << ");" << std::endl;
|
||||
}
|
||||
|
||||
/* Disable the address and din */
|
||||
/* Disable the address and din
|
||||
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
|
||||
fp << "(" << addr_port.get_width() << "'b";
|
||||
std::vector<size_t> all_zero_addr(addr_port.get_width(), 0);
|
||||
|
@ -1756,8 +1694,9 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
|
|||
fp << addr_bit;
|
||||
}
|
||||
fp << ", ";
|
||||
fp <<"1'b0";
|
||||
fp << generate_verilog_constant_values(initial_din_values);
|
||||
fp << ");" << std::endl;
|
||||
*/
|
||||
|
||||
/* Raise the flag of configuration done when bitstream loading is complete */
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||
|
|
|
@ -64,4 +64,172 @@ size_t find_configuration_chain_fabric_bitstream_size_to_be_skipped(const Fabric
|
|||
return num_bits_to_skip;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Reorganize the fabric bitstream for frame-based protocol
|
||||
* by the same address across regions:
|
||||
* This is due to that the length of fabric bitstream could be different in each region.
|
||||
* Template:
|
||||
* <address> <din_values_from_different_regions>
|
||||
* An example:
|
||||
* 000000 1011
|
||||
*
|
||||
* Note: the std::map may cause large memory footprint for large bitstream databases!
|
||||
*******************************************************************/
|
||||
std::map<std::string, std::vector<bool>> build_frame_based_fabric_bitstream_by_address(const FabricBitstream& fabric_bitstream) {
|
||||
std::map<std::string, std::vector<bool>> fabric_bits_by_addr;
|
||||
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) {
|
||||
/* Create string for address */
|
||||
std::string addr_str;
|
||||
for (const char& addr_bit : fabric_bitstream.bit_address(bit_id)) {
|
||||
addr_str.push_back(addr_bit);
|
||||
}
|
||||
|
||||
/* Place the config bit */
|
||||
auto result = fabric_bits_by_addr.find(addr_str);
|
||||
if (result == fabric_bits_by_addr.end()) {
|
||||
/* This is a new bit, resize the vector to the number of regions
|
||||
* and deposit '0' to all the bits
|
||||
*/
|
||||
fabric_bits_by_addr[addr_str] = std::vector<bool>(fabric_bitstream.regions().size(), false);
|
||||
fabric_bits_by_addr[addr_str][size_t(region)] = fabric_bitstream.bit_din(bit_id);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(result != fabric_bits_by_addr.end());
|
||||
result->second[size_t(region)] = fabric_bitstream.bit_din(bit_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fabric_bits_by_addr;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* For fast configuration, the number of bits to be skipped
|
||||
* the rule to skip any configuration bit should consider the whole data input values.
|
||||
* Only all the bits in the din port match the value to be skipped,
|
||||
* the programming cycle can be skipped!
|
||||
* For example:
|
||||
* Address: 010101
|
||||
* Region 0: 0
|
||||
* Region 1: 1
|
||||
* Region 2: 0
|
||||
* This bit cannot be skipped if the bit_value_to_skip is 0
|
||||
*
|
||||
* Address: 010101
|
||||
* Region 0: 0
|
||||
* Region 1: 0
|
||||
* Region 2: 0
|
||||
* This bit can be skipped if the bit_value_to_skip is 0
|
||||
*******************************************************************/
|
||||
size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBitstream& fabric_bitstream,
|
||||
const bool& bit_value_to_skip) {
|
||||
std::map<std::string, std::vector<bool>> fabric_bits_by_addr = build_frame_based_fabric_bitstream_by_address(fabric_bitstream);
|
||||
|
||||
size_t num_bits = 0;
|
||||
|
||||
for (const auto& addr_din_pair : fabric_bits_by_addr) {
|
||||
bool skip_curr_bits = true;
|
||||
for (const bool& bit : addr_din_pair.second) {
|
||||
if (bit_value_to_skip != bit) {
|
||||
skip_curr_bits = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (false == skip_curr_bits) {
|
||||
num_bits++;
|
||||
}
|
||||
}
|
||||
|
||||
return num_bits;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Reorganize the fabric bitstream for memory banks
|
||||
* by the same address across regions:
|
||||
* This is due to that the length of fabric bitstream could be different in each region.
|
||||
* Template:
|
||||
* <bl_address> <wl_address> <din_values_from_different_regions>
|
||||
* An example:
|
||||
* 000000 00000 1011
|
||||
*
|
||||
* Note: the std::map may cause large memory footprint for large bitstream databases!
|
||||
*******************************************************************/
|
||||
std::map<std::pair<std::string, std::string>, std::vector<bool>> build_memory_bank_fabric_bitstream_by_address(const FabricBitstream& fabric_bitstream) {
|
||||
std::map<std::pair<std::string, std::string>, std::vector<bool>> fabric_bits_by_addr;
|
||||
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) {
|
||||
/* Create string for BL address */
|
||||
std::string bl_addr_str;
|
||||
for (const char& addr_bit : fabric_bitstream.bit_bl_address(bit_id)) {
|
||||
bl_addr_str.push_back(addr_bit);
|
||||
}
|
||||
|
||||
/* Create string for WL address */
|
||||
std::string wl_addr_str;
|
||||
for (const char& addr_bit : fabric_bitstream.bit_wl_address(bit_id)) {
|
||||
wl_addr_str.push_back(addr_bit);
|
||||
}
|
||||
|
||||
/* Place the config bit */
|
||||
auto result = fabric_bits_by_addr.find(std::make_pair(bl_addr_str, wl_addr_str));
|
||||
if (result == fabric_bits_by_addr.end()) {
|
||||
/* This is a new bit, resize the vector to the number of regions
|
||||
* and deposit '0' to all the bits
|
||||
*/
|
||||
fabric_bits_by_addr[std::make_pair(bl_addr_str, wl_addr_str)] = std::vector<bool>(fabric_bitstream.regions().size(), false);
|
||||
fabric_bits_by_addr[std::make_pair(bl_addr_str, wl_addr_str)][size_t(region)] = fabric_bitstream.bit_din(bit_id);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(result != fabric_bits_by_addr.end());
|
||||
result->second[size_t(region)] = fabric_bitstream.bit_din(bit_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fabric_bits_by_addr;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* For fast configuration, the number of bits to be skipped
|
||||
* the rule to skip any configuration bit should consider the whole data input values.
|
||||
* Only all the bits in the din port match the value to be skipped,
|
||||
* the programming cycle can be skipped!
|
||||
* For example:
|
||||
* BL Address: 010101
|
||||
* WL Address: 010101
|
||||
* Region 0: 0
|
||||
* Region 1: 1
|
||||
* Region 2: 0
|
||||
* This bit cannot be skipped if the bit_value_to_skip is 0
|
||||
*
|
||||
* BL Address: 010101
|
||||
* WL Address: 010101
|
||||
* Region 0: 0
|
||||
* Region 1: 0
|
||||
* Region 2: 0
|
||||
* This bit can be skipped if the bit_value_to_skip is 0
|
||||
*******************************************************************/
|
||||
size_t find_memory_bank_fast_configuration_fabric_bitstream_size(const FabricBitstream& fabric_bitstream,
|
||||
const bool& bit_value_to_skip) {
|
||||
std::map<std::pair<std::string, std::string>, std::vector<bool>> fabric_bits_by_addr = build_memory_bank_fabric_bitstream_by_address(fabric_bitstream);
|
||||
|
||||
size_t num_bits = 0;
|
||||
|
||||
for (const auto& addr_din_pair : fabric_bits_by_addr) {
|
||||
bool skip_curr_bits = true;
|
||||
for (const bool& bit : addr_din_pair.second) {
|
||||
if (bit_value_to_skip != bit) {
|
||||
skip_curr_bits = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (false == skip_curr_bits) {
|
||||
num_bits++;
|
||||
}
|
||||
}
|
||||
|
||||
return num_bits;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "bitstream_manager.h"
|
||||
#include "fabric_bitstream.h"
|
||||
|
||||
|
@ -24,6 +25,16 @@ size_t find_configuration_chain_fabric_bitstream_size_to_be_skipped(const Fabric
|
|||
const BitstreamManager& bitstream_manager,
|
||||
const bool& bit_value_to_skip);
|
||||
|
||||
std::map<std::string, std::vector<bool>> build_frame_based_fabric_bitstream_by_address(const FabricBitstream& fabric_bitstream);
|
||||
|
||||
size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBitstream& fabric_bitstream,
|
||||
const bool& bit_value_to_skip);
|
||||
|
||||
std::map<std::pair<std::string, std::string>, std::vector<bool>> build_memory_bank_fabric_bitstream_by_address(const FabricBitstream& fabric_bitstream);
|
||||
|
||||
size_t find_memory_bank_fast_configuration_fabric_bitstream_size(const FabricBitstream& fabric_bitstream,
|
||||
const bool& bit_value_to_skip);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue