[FPGA-Bitstream] Upgraded bitstream writer to support QuickLogic memory bank using shift registers

This commit is contained in:
tangxifan 2021-09-30 21:05:41 -07:00
parent 4526133089
commit 33972fc0ec
8 changed files with 166 additions and 42 deletions

View File

@ -1323,13 +1323,19 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module
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];
/* 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;
sr_banks.add_shift_register_sink_nodes(config_region, sr_bank_module, cur_inst, child_id, sink_bl_pin);
sr_banks.add_shift_register_sink_blwls(config_region, sr_bank_module, cur_inst, bl_pin_id);
}
}
}
@ -1409,13 +1415,18 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module
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];
/* Find the BL port */
size_t cur_wl_index = 0;
/* 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);
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;
sr_banks.add_shift_register_sink_nodes(config_region, sr_bank_module, cur_inst, child_id, sink_wl_pin);
sr_banks.add_shift_register_sink_blwls(config_region, sr_bank_module, cur_inst, wl_pin_id);
}
}
}

View File

@ -7,7 +7,7 @@ namespace openfpga {
std::vector<ModuleId> MemoryBankShiftRegisterBanks::shift_register_bank_unique_modules() const {
std::vector<ModuleId> sr_bank_modules;
for (const auto& region : sr_instance_info_) {
for (const auto& region : sr_instance_sink_child_ids_) {
for (const auto& pair : region) {
if (sr_bank_modules.end() == std::find(sr_bank_modules.begin(), sr_bank_modules.end(), pair.first.first)) {
sr_bank_modules.push_back(pair.first.first);
@ -20,7 +20,7 @@ std::vector<ModuleId> MemoryBankShiftRegisterBanks::shift_register_bank_unique_m
std::vector<ModuleId> MemoryBankShiftRegisterBanks::shift_register_bank_modules(const ConfigRegionId& region) const {
std::vector<ModuleId> sr_bank_modules;
VTR_ASSERT(valid_region_id(region));
for (const auto& pair : sr_instance_info_[region]) {
for (const auto& pair : sr_instance_sink_child_ids_[region]) {
sr_bank_modules.push_back(pair.first.first);
}
return sr_bank_modules;
@ -29,7 +29,7 @@ std::vector<ModuleId> MemoryBankShiftRegisterBanks::shift_register_bank_modules(
std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_instances(const ConfigRegionId& region) const {
std::vector<size_t> sr_bank_instances;
VTR_ASSERT(valid_region_id(region));
for (const auto& pair : sr_instance_info_[region]) {
for (const auto& pair : sr_instance_sink_child_ids_[region]) {
sr_bank_instances.push_back(pair.first.second);
}
return sr_bank_instances;
@ -39,43 +39,41 @@ std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_sink_child
const ModuleId& sr_module,
const size_t& sr_instance) const {
VTR_ASSERT(valid_region_id(region));
std::vector<size_t> sink_child_ids;
auto result = sr_instance_info_[region].find(std::make_pair(sr_module, sr_instance));
auto result = sr_instance_sink_child_ids_[region].find(std::make_pair(sr_module, sr_instance));
/* Return an empty vector if not found */
if (result != sr_instance_info_[region].end()) {
for (const auto& sink_child : result->second) {
sink_child_ids.push_back(sink_child.first);
}
if (result != sr_instance_sink_child_ids_[region].end()) {
return result->second;
}
return sink_child_ids;
return std::vector<size_t>();
}
std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_sink_pin_ids(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance) const {
VTR_ASSERT(valid_region_id(region));
std::vector<size_t> sink_child_pin_ids;
auto result = sr_instance_info_[region].find(std::make_pair(sr_module, sr_instance));
auto result = sr_instance_sink_child_pin_ids_[region].find(std::make_pair(sr_module, sr_instance));
/* Return an empty vector if not found */
if (result != sr_instance_info_[region].end()) {
for (const auto& sink_child : result->second) {
sink_child_pin_ids.push_back(sink_child.second);
}
if (result != sr_instance_sink_child_pin_ids_[region].end()) {
return result->second;
}
return sink_child_pin_ids;
return std::vector<size_t>();
}
void MemoryBankShiftRegisterBanks::resize_regions(const size_t& num_regions) {
sr_instance_info_.resize(num_regions);
sr_instance_sink_child_ids_.resize(num_regions);
sr_instance_sink_child_pin_ids_.resize(num_regions);
sr_instance_sink_blwl_ids_.resize(num_regions);
}
void MemoryBankShiftRegisterBanks::add_shift_register_instance(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance) {
VTR_ASSERT(valid_region_id(region));
sr_instance_info_[region][std::make_pair(sr_module, sr_instance)];
sr_instance_sink_child_ids_[region][std::make_pair(sr_module, sr_instance)];
sr_instance_sink_child_pin_ids_[region][std::make_pair(sr_module, sr_instance)];
sr_instance_sink_blwl_ids_[region][std::make_pair(sr_module, sr_instance)];
}
void MemoryBankShiftRegisterBanks::add_shift_register_sink_nodes(const ConfigRegionId& region,
@ -84,11 +82,20 @@ void MemoryBankShiftRegisterBanks::add_shift_register_sink_nodes(const ConfigReg
const size_t& sink_child_id,
const size_t& sink_child_pin_id) {
VTR_ASSERT(valid_region_id(region));
sr_instance_info_[region][std::make_pair(sr_module, sr_instance)].push_back(std::make_pair(sink_child_id, sink_child_pin_id));
sr_instance_sink_child_ids_[region][std::make_pair(sr_module, sr_instance)].push_back(sink_child_id);
sr_instance_sink_child_pin_ids_[region][std::make_pair(sr_module, sr_instance)].push_back(sink_child_pin_id);
}
void MemoryBankShiftRegisterBanks::add_shift_register_sink_blwls(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance,
const size_t& sink_blwl_id) {
VTR_ASSERT(valid_region_id(region));
sr_instance_sink_blwl_ids_[region][std::make_pair(sr_module, sr_instance)].push_back(sink_blwl_id);
}
bool MemoryBankShiftRegisterBanks::valid_region_id(const ConfigRegionId& region) const {
return size_t(region) < sr_instance_info_.size();
return size_t(region) < sr_instance_sink_child_ids_.size();
}
} /* end namespace openfpga */

View File

@ -52,18 +52,26 @@ class MemoryBankShiftRegisterBanks {
const ModuleId& sr_module,
const size_t& sr_instance);
/* @brief Add the module id and instance id of a shift register under a specific configuration region of top-level module */
/* @brief Add the child id and pin id of BL/WL to which a shift register is connected to under a specific configuration region of top-level module */
void add_shift_register_sink_nodes(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance,
const size_t& sink_child_id,
const size_t& sink_child_pin_id);
/* @brief Add the BL/WL id under a specific configuration region of top-level module to which a shift register is connected to */
void add_shift_register_sink_blwls(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance,
const size_t& sink_blwl_id);
public: /* Validators */
bool valid_region_id(const ConfigRegionId& region) const;
private: /* Internal data */
/* [config_region][(shift_register_module, shift_register_instance)][i] = (reconfigurable_child_id, blwl_port_pin_index)*/
vtr::vector<ConfigRegionId, std::map<std::pair<ModuleId, size_t>, std::vector<std::pair<size_t, size_t>>>> sr_instance_info_;
vtr::vector<ConfigRegionId, std::map<std::pair<ModuleId, size_t>, std::vector<size_t>>> sr_instance_sink_child_ids_;
vtr::vector<ConfigRegionId, std::map<std::pair<ModuleId, size_t>, std::vector<size_t>>> sr_instance_sink_child_pin_ids_;
vtr::vector<ConfigRegionId, std::map<std::pair<ModuleId, size_t>, std::vector<size_t>>> sr_instance_sink_blwl_ids_;
};
} /* end namespace openfpga */

View File

@ -43,6 +43,16 @@ std::vector<std::string> MemoryBankShiftRegisterFabricBitstream::wl_vectors(cons
return bitstream_word_wls_[word_id];
}
std::vector<std::string> MemoryBankShiftRegisterFabricBitstream::blwl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const {
VTR_ASSERT(valid_word_id(word_id));
std::vector<std::string> blwl_vec = bitstream_word_bls_[word_id];
VTR_ASSERT(blwl_vec.size() == bitstream_word_wls_[word_id].size());
for (size_t iwl = 0; iwl < bitstream_word_wls_[word_id].size(); ++iwl) {
blwl_vec[iwl] += bitstream_word_wls_[word_id][iwl];
}
return blwl_vec;
}
MemoryBankShiftRegisterFabricBitstreamWordId MemoryBankShiftRegisterFabricBitstream::create_word() {
/* Create a new id*/
MemoryBankShiftRegisterFabricBitstreamWordId word_id = MemoryBankShiftRegisterFabricBitstreamWordId(bitstream_word_ids_.size());
@ -59,14 +69,12 @@ MemoryBankShiftRegisterFabricBitstreamWordId MemoryBankShiftRegisterFabricBitstr
void MemoryBankShiftRegisterFabricBitstream::add_bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id,
const std::string& bl_vec) {
VTR_ASSERT(valid_word_id(word_id));
VTR_ASSERT(bl_vec.size() == bl_width());
return bitstream_word_bls_[word_id].push_back(bl_vec);
}
void MemoryBankShiftRegisterFabricBitstream::add_wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id,
const std::string& wl_vec) {
VTR_ASSERT(valid_word_id(word_id));
VTR_ASSERT(wl_vec.size() == wl_width());
return bitstream_word_wls_[word_id].push_back(wl_vec);
}

View File

@ -43,6 +43,9 @@ class MemoryBankShiftRegisterFabricBitstream {
/* @brief Return the WL vectors in a given word id */
std::vector<std::string> wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const;
/* @brief Return the pair of BL and WL vectors in a given word id */
std::vector<std::string> blwl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const;
public: /* Mutators */
/* @brief Create a new word */
MemoryBankShiftRegisterFabricBitstreamWordId create_word();

View File

@ -238,26 +238,23 @@ int write_memory_bank_shift_register_fabric_bitstream_to_text_file(std::fstream&
const FabricBitstream& fabric_bitstream) {
int status = 0;
MemoryBankFlattenFabricBitstream fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip);
size_t bl_addr_size = fabric_bits.bl_vector_size();
size_t wl_addr_size = fabric_bits.wl_vector_size();
MemoryBankShiftRegisterFabricBitstream fabric_bits = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream, bit_value_to_skip);
/* Output information about how to intepret the bitstream */
fp << "// Bitstream length: " << fabric_bits.size() << std::endl;
fp << "// Bitstream word count: " << fabric_bits.num_words() << std::endl;
fp << "// Bitstream word size: " << fabric_bits.word_size() << std::endl;
fp << "// Bitstream width (LSB -> MSB): ";
fp << "<bl shift register heads" << bl_addr_size << " bits>";
fp << "<wl shift register heads " << wl_addr_size << " bits>";
fp << "<bl shift register heads" << fabric_bits.bl_width() << " bits>";
fp << "<wl shift register heads " << fabric_bits.wl_width() << " bits>";
fp << std::endl;
for (const auto& wl_vec : fabric_bits.wl_vectors()) {
/* Write BL address code */
for (const auto& bl_unit : fabric_bits.bl_vector(wl_vec)) {
fp << bl_unit;
}
/* Write WL address code */
for (const auto& wl_unit : wl_vec) {
fp << wl_unit;
size_t word_cnt = 0;
for (const auto& word : fabric_bits.words()) {
fp << "// Word " << word_cnt << std::endl;
/* Write BL/WL address code */
for (const auto& blwl_vec : fabric_bits.blwl_vectors(word)) {
fp << blwl_vec;
}
fp << std::endl;
}

View File

@ -319,6 +319,61 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons
return fabric_bits;
}
MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_bitstream(const FabricBitstream& fabric_bitstream,
//const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
const bool& bit_value_to_skip) {
MemoryBankFlattenFabricBitstream raw_fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip);
MemoryBankShiftRegisterFabricBitstream fabric_bits;
/* Iterate over each word */
for (const auto& wl_vec : raw_fabric_bits.wl_vectors()) {
std::vector<std::string> bl_vec = raw_fabric_bits.bl_vector(wl_vec);
/* Find the max sizes of BL/WL bits, this determines the size of shift register chain */
size_t max_blwl_sizes = 0;
for (const auto& bl_bits : bl_vec) {
max_blwl_sizes = std::max(max_blwl_sizes, bl_bits.size());
}
for (const auto& wl_bits : wl_vec) {
max_blwl_sizes = std::max(max_blwl_sizes, wl_bits.size());
}
/* Reshape the BL and WL vectors */
std::vector<std::string> reshaped_blwls(bl_vec.size() + wl_vec.size(), std::string(max_blwl_sizes, '0'));
size_t blwl_col_cnt = 0;
for (const auto& bl_bits : bl_vec) {
size_t offset = max_blwl_sizes - bl_vec.size();
for (const char& bl_bit : bl_bits) {
reshaped_blwls[blwl_col_cnt][offset] = bl_bit;
offset++;
}
blwl_col_cnt++;
}
for (const auto& wl_bits : wl_vec) {
size_t offset = max_blwl_sizes - wl_vec.size();
for (const char& wl_bit : wl_bits) {
reshaped_blwls[blwl_col_cnt][offset] = wl_bit;
offset++;
}
blwl_col_cnt++;
}
/* Add the word to final bitstream */
MemoryBankShiftRegisterFabricBitstreamWordId word_id = fabric_bits.create_word();
for (size_t irow = 0; irow < max_blwl_sizes; ++irow) {
std::string cur_bl_vec;
for (size_t icol = 0; icol < bl_vec.size(); ++icol) {
cur_bl_vec.push_back(reshaped_blwls[icol][irow]);
}
fabric_bits.add_bl_vectors(word_id, cur_bl_vec);
std::string cur_wl_vec;
for (size_t icol = bl_vec.size(); icol < bl_vec.size() + wl_vec.size(); ++icol) {
cur_wl_vec.push_back(reshaped_blwls[icol][irow]);
}
fabric_bits.add_wl_vectors(word_id, cur_wl_vec);
}
}
return fabric_bits;
}
/********************************************************************
* For fast configuration, the number of bits to be skipped

View File

@ -9,8 +9,11 @@
*******************************************************************/
#include <vector>
#include <map>
#include <array>
#include "bitstream_manager.h"
#include "memory_bank_flatten_fabric_bitstream.h"
#include "memory_bank_shift_register_banks.h"
#include "memory_bank_shift_register_fabric_bitstream.h"
#include "fabric_bitstream.h"
/********************************************************************
@ -39,7 +42,7 @@ size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBit
const bool& bit_value_to_skip);
/********************************************************************
* @ brief Reorganize the fabric bitstream for memory banks which use flatten or shift register to manipulate BL and WLs
* @ brief Reorganize the fabric bitstream for memory banks which use flatten BL and WLs
* For each configuration region, we will merge BL address (which are 1-hot codes) under the same WL address
*
* Quick Example
@ -61,6 +64,38 @@ size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBit
MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream,
const bool& bit_value_to_skip);
/********************************************************************
* @ brief Reorganize the fabric bitstream for memory banks which use shift register to manipulate BL and WLs
* For each configuration region, we will merge BL address (which are 1-hot codes) under the same WL address
*
* Quick Example
* <bl of region A>_<bl of region B> <wl of region A>_<wl of region B>
* An example:
* 010_111 000_101
*
* Note that all the BL/WLs across configuration regions are independent. We will combine them together
* Quick Example
* <bl of region A>_<bl of region B> <wl of region A>_<wl of region B>
* 001_010 000_000
* 100_100 000_000
*
* the bitstream will be merged as
* 101_110 000_000
*
* Because that the BL/WL are loaded through shift registers (perhaps using multiple heads), the bitstream will be reorganized as
* Considering single head:
*
* <bl of region A>_<bl of region B> <wl of region A>_<wl of region B>
* 1_1 0_0
* 0_1 0_0
* 1_0 0_0
*
* @note the std::map may cause large memory footprint for large bitstream databases!
*******************************************************************/
MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_bitstream(const FabricBitstream& fabric_bitstream,
//const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
const bool& bit_value_to_skip);
/* Alias to a specific organization of bitstreams for memory bank configuration protocol */
typedef std::map<std::pair<std::string, std::string>, std::vector<bool>> MemoryBankFabricBitstream;
MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const FabricBitstream& fabric_bitstream);