From 33972fc0ec11d73ec892ff852bd9f0ebfb98d8af Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 30 Sep 2021 21:05:41 -0700 Subject: [PATCH] [FPGA-Bitstream] Upgraded bitstream writer to support QuickLogic memory bank using shift registers --- .../fabric/build_top_module_memory_bank.cpp | 13 ++++- .../memory_bank_shift_register_banks.cpp | 49 ++++++++++------- .../fabric/memory_bank_shift_register_banks.h | 12 +++- ...y_bank_shift_register_fabric_bitstream.cpp | 12 +++- ...ory_bank_shift_register_fabric_bitstream.h | 3 + .../write_text_fabric_bitstream.cpp | 27 ++++----- openfpga/src/utils/fabric_bitstream_utils.cpp | 55 +++++++++++++++++++ openfpga/src/utils/fabric_bitstream_utils.h | 37 ++++++++++++- 8 files changed, 166 insertions(+), 42 deletions(-) diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index dd2bdf29b..206a70728 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -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 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 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); } } } diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp index 0d4902936..aac8989fe 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp @@ -7,7 +7,7 @@ namespace openfpga { std::vector MemoryBankShiftRegisterBanks::shift_register_bank_unique_modules() const { std::vector 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 MemoryBankShiftRegisterBanks::shift_register_bank_unique_m std::vector MemoryBankShiftRegisterBanks::shift_register_bank_modules(const ConfigRegionId& region) const { std::vector 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 MemoryBankShiftRegisterBanks::shift_register_bank_modules( std::vector MemoryBankShiftRegisterBanks::shift_register_bank_instances(const ConfigRegionId& region) const { std::vector 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 MemoryBankShiftRegisterBanks::shift_register_bank_sink_child const ModuleId& sr_module, const size_t& sr_instance) const { VTR_ASSERT(valid_region_id(region)); - std::vector 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(); } std::vector 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 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(); } 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 */ diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.h b/openfpga/src/fabric/memory_bank_shift_register_banks.h index 59c92fef7..a145aca5e 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.h +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.h @@ -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, std::vector>>> sr_instance_info_; + vtr::vector, std::vector>> sr_instance_sink_child_ids_; + vtr::vector, std::vector>> sr_instance_sink_child_pin_ids_; + vtr::vector, std::vector>> sr_instance_sink_blwl_ids_; }; } /* end namespace openfpga */ diff --git a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp index 06c3c4aea..9d5f5fe63 100644 --- a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp @@ -43,6 +43,16 @@ std::vector MemoryBankShiftRegisterFabricBitstream::wl_vectors(cons return bitstream_word_wls_[word_id]; } +std::vector MemoryBankShiftRegisterFabricBitstream::blwl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const { + VTR_ASSERT(valid_word_id(word_id)); + std::vector 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); } diff --git a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h index b6355ccad..1355a8274 100644 --- a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h +++ b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h @@ -43,6 +43,9 @@ class MemoryBankShiftRegisterFabricBitstream { /* @brief Return the WL vectors in a given word id */ std::vector wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const; + /* @brief Return the pair of BL and WL vectors in a given word id */ + std::vector blwl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const; + public: /* Mutators */ /* @brief Create a new word */ MemoryBankShiftRegisterFabricBitstreamWordId create_word(); diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index a25b5ad02..3c6de650f 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -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 << ""; - fp << ""; + fp << ""; + fp << ""; 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; } diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index b300919a4..6ad0017a7 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -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& 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 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 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 diff --git a/openfpga/src/utils/fabric_bitstream_utils.h b/openfpga/src/utils/fabric_bitstream_utils.h index d21c9c12e..9a97a078b 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.h +++ b/openfpga/src/utils/fabric_bitstream_utils.h @@ -9,8 +9,11 @@ *******************************************************************/ #include #include +#include #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 + * _ _ + * An example: + * 010_111 000_101 + * + * Note that all the BL/WLs across configuration regions are independent. We will combine them together + * Quick Example + * _ _ + * 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: + * + * _ _ + * 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& 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::vector> MemoryBankFabricBitstream; MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const FabricBitstream& fabric_bitstream);