242 lines
9.6 KiB
C++
242 lines
9.6 KiB
C++
/************************************************************************
|
|
* Function to perform fundamental operation for fabric bitstream class
|
|
* These functions are not universal methods for the FabricBitstream class
|
|
* They are made to ease the development in some specific purposes
|
|
* Please classify such functions in this file
|
|
***********************************************************************/
|
|
|
|
#include <algorithm>
|
|
|
|
/* Headers from vtrutil library */
|
|
#include "vtr_assert.h"
|
|
#include "vtr_log.h"
|
|
|
|
/* Headers from openfpgautil library */
|
|
#include "openfpga_decode.h"
|
|
|
|
#include "fabric_bitstream_utils.h"
|
|
|
|
/* begin namespace openfpga */
|
|
namespace openfpga {
|
|
|
|
/********************************************************************
|
|
* Find the longest bitstream size of a fabric bitstream
|
|
*******************************************************************/
|
|
size_t find_fabric_regional_bitstream_max_size(const FabricBitstream& fabric_bitstream) {
|
|
size_t regional_bitstream_max_size = 0;
|
|
/* Find the longest regional bitstream */
|
|
for (const auto& region : fabric_bitstream.regions()) {
|
|
if (regional_bitstream_max_size < fabric_bitstream.region_bits(region).size()) {
|
|
regional_bitstream_max_size = fabric_bitstream.region_bits(region).size();
|
|
}
|
|
}
|
|
return regional_bitstream_max_size;
|
|
}
|
|
|
|
/********************************************************************
|
|
* For fast configuration, the number of bits to be skipped
|
|
* depends on each regional bitstream
|
|
* For example:
|
|
* Region 0: 000000001111101010
|
|
* Region 1: 00000011010101
|
|
* Region 2: 0010101111000110
|
|
* The number of bits that can be skipped is limited by Region 2
|
|
* Find the longest bitstream size of a fabric bitstream
|
|
*******************************************************************/
|
|
size_t find_configuration_chain_fabric_bitstream_size_to_be_skipped(const FabricBitstream& fabric_bitstream,
|
|
const BitstreamManager& bitstream_manager,
|
|
const bool& bit_value_to_skip) {
|
|
size_t regional_bitstream_max_size = find_fabric_regional_bitstream_max_size(fabric_bitstream);
|
|
|
|
size_t num_bits_to_skip = size_t(-1);
|
|
for (const auto& region : fabric_bitstream.regions()) {
|
|
size_t curr_region_num_bits_to_skip = 0;
|
|
for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) {
|
|
if (bit_value_to_skip != bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id))) {
|
|
break;
|
|
}
|
|
curr_region_num_bits_to_skip++;
|
|
}
|
|
/* For regional bitstream which is short than the longest region bitstream,
|
|
* The number of bits to skip
|
|
*/
|
|
curr_region_num_bits_to_skip += regional_bitstream_max_size - fabric_bitstream.region_bits(region).size();
|
|
num_bits_to_skip = std::min(curr_region_num_bits_to_skip, num_bits_to_skip);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/* Expand all the don't care bits */
|
|
for (const std::string& curr_addr_str : expand_dont_care_bin_str(addr_str)) {
|
|
/* Place the config bit */
|
|
auto result = fabric_bits_by_addr.find(curr_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[curr_addr_str] = std::vector<bool>(fabric_bitstream.regions().size(), false);
|
|
fabric_bits_by_addr[curr_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 */
|