diff --git a/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp b/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp index 09ae2e966..d4befa8bb 100644 --- a/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp +++ b/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp @@ -302,6 +302,7 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol /* TODO */ VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()); } + BasicPort cur_bl_addr_port_info = module_manager.module_port(top_module, cur_bl_addr_port); ModulePortId cur_wl_addr_port; if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) { diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp index ca3702a3e..23530f627 100644 --- a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp @@ -144,7 +144,7 @@ void FabricBitstream::set_bit_address(const FabricBitId& bit_id, VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == use_address_); if (tolerant_short_address) { - VTR_ASSERT(address_length_ => address.size()); + VTR_ASSERT(address_length_ >= address.size()); } else { VTR_ASSERT(address_length_ == address.size()); } @@ -164,7 +164,7 @@ void FabricBitstream::set_bit_wl_address(const FabricBitId& bit_id, VTR_ASSERT(true == use_address_); VTR_ASSERT(true == use_wl_address_); if (tolerant_short_address) { - VTR_ASSERT(wl_address_length_ => address.size()); + VTR_ASSERT(wl_address_length_ >= address.size()); } else { VTR_ASSERT(wl_address_length_ == address.size()); } diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index 8130fb447..13ef05726 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -190,29 +190,40 @@ int write_memory_bank_fabric_bitstream_to_text_file(std::fstream& fp, *******************************************************************/ static int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp, + const bool& bit_value_to_skip, const FabricBitstream& fabric_bitstream) { int status = 0; - MemoryBankFabricBitstream fabric_bits_by_addr = build_memory_bank_fabric_bitstream_by_address(fabric_bitstream); + MemoryBankFlattenFabricBitstream fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip); /* The address sizes and data input sizes are the same across any element, * just get it from the 1st element to save runtime */ - size_t bl_addr_size = fabric_bits_by_addr.begin()->first.first.size(); - size_t wl_addr_size = fabric_bits_by_addr.begin()->first.second.size(); + size_t bl_addr_size = 0; + for (const auto& bl_vec : fabric_bits.begin()->first) { + bl_addr_size += bl_vec.size(); + } + size_t wl_addr_size = 0; + for (const auto& wl_vec : fabric_bits.begin()->second) { + wl_addr_size += wl_vec.size(); + } /* Output information about how to intepret the bitstream */ - fp << "// Bitstream length: " << fabric_bits_by_addr.size() << std::endl; + fp << "// Bitstream length: " << fabric_bits.size() << std::endl; fp << "// Bitstream width (LSB -> MSB): "; fp << ""; fp << ""; fp << std::endl; - for (const auto& addr_din_pair : fabric_bits_by_addr) { + for (const auto& addr_pair : fabric_bits) { /* Write BL address code */ - fp << addr_din_pair.first.first; + for (const auto& bl_vec : addr_pair.first) { + fp << bl_vec; + } /* Write WL address code */ - fp << addr_din_pair.first.second; + for (const auto& wl_vec : addr_pair.second) { + fp << wl_vec; + } fp << std::endl; } @@ -362,6 +373,7 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage VTR_ASSERT(BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type() || BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()); status = write_memory_bank_flatten_fabric_bitstream_to_text_file(fp, + bit_value_to_skip, fabric_bitstream); } break; diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index 4fb46f0cf..bd518c7b2 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -232,12 +232,17 @@ MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const Fa return fabric_bits_by_addr; } -MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream) { +MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream, + const bool& bit_value_to_skip) { /* Build the bitstream by each region, here we use (WL, BL) pairs when storing bitstreams */ vtr::vector> fabric_bits_per_region; fabric_bits_per_region.resize(fabric_bitstream.num_regions()); for (const FabricBitRegionId& region : fabric_bitstream.regions()) { for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) { + /* Skip din because they should be pre-configured through programming reset/set */ + if ((fabric_bitstream.bit_din(bit_id) == '1') == bit_value_to_skip) { + continue; + } /* Create string for BL address */ std::string bl_addr_str; for (const char& addr_bit : fabric_bitstream.bit_bl_address(bit_id)) { @@ -264,8 +269,55 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons } } - /* TODO: Combine the bitstream from different region into a unique one. Now we follow the convention: use (BL, WL) pairs */ + /* Find all the keys for the hash tables containing bitstream of each region */ + vtr::vector> fabric_bits_per_region_keys; + fabric_bits_per_region_keys.resize(fabric_bitstream.num_regions()); + for (const FabricBitRegionId& region : fabric_bitstream.regions()) { + /* Pre-allocate memory, because the key size may be large */ + fabric_bits_per_region_keys[region].reserve(fabric_bits_per_region[region].size()); + for (const auto& pair : fabric_bits_per_region[region]) { + fabric_bits_per_region_keys[region].push_back(pair.first); + } + } + + /* Find the maxium key size */ + size_t max_key_size = 0; + for (const FabricBitRegionId& region : fabric_bitstream.regions()) { + max_key_size = std::max(max_key_size, fabric_bits_per_region_keys[region].size()); + } + + /* Find the BL/WL sizes per region; Pair convention is (BL, WL) + * The address sizes are the same across any element, + * just get it from the 1st element to save runtime + */ + vtr::vector> max_blwl_sizes_per_region; + max_blwl_sizes_per_region.resize(fabric_bitstream.num_regions()); + for (const FabricBitRegionId& region : fabric_bitstream.regions()) { + max_blwl_sizes_per_region[region].first = std::max(max_blwl_sizes_per_region[region].first, fabric_bits_per_region[region].begin()->second.size()); + max_blwl_sizes_per_region[region].second = std::max(max_blwl_sizes_per_region[region].second, fabric_bits_per_region[region].begin()->first.size()); + } + + /* Combine the bitstream from different region into a unique one. Now we follow the convention: use (BL, WL) pairs */ MemoryBankFlattenFabricBitstream fabric_bits; + for (size_t ikey = 0; ikey < max_key_size; ikey++) { + /* Prepare the final BL/WL vectors to be added to the bitstream database */ + std::vector cur_bl_vectors; + std::vector cur_wl_vectors; + for (const FabricBitRegionId& region : fabric_bitstream.regions()) { + /* If the key id is in bound for the key list in this region, find the BL and WL and add to the final bitstream database + * If the key id is out of bound for the key list in this region, we append an all-zero string for both BL and WLs + */ + if (ikey < fabric_bits_per_region_keys[region].size()) { + cur_wl_vectors.push_back(fabric_bits_per_region_keys[region][ikey]); + cur_bl_vectors.push_back(fabric_bits_per_region[region].at(fabric_bits_per_region_keys[region][ikey])); + } else { + cur_wl_vectors.push_back(std::string(max_blwl_sizes_per_region[region].second, '0')); + cur_bl_vectors.push_back(std::string(max_blwl_sizes_per_region[region].first, '0')); + } + } + /* Add the pair to std map */ + fabric_bits[cur_bl_vectors] = cur_wl_vectors; + } return fabric_bits; } diff --git a/openfpga/src/utils/fabric_bitstream_utils.h b/openfpga/src/utils/fabric_bitstream_utils.h index ca23a5363..cb3406347 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.h +++ b/openfpga/src/utils/fabric_bitstream_utils.h @@ -58,7 +58,8 @@ size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBit * @note the std::map may cause large memory footprint for large bitstream databases! *******************************************************************/ typedef std::map, std::vector> MemoryBankFlattenFabricBitstream; -MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream); +MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream, + const bool& bit_value_to_skip); /* Alias to a specific organization of bitstreams for memory bank configuration protocol */ typedef std::map, std::vector> MemoryBankFabricBitstream;