From 51e1559352c5a64e909ca391622c8550c1e51088 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 30 May 2020 19:12:46 -0600 Subject: [PATCH] add fabric bitstream support for memory bank configuration protocol --- .../fpga_bitstream/build_fabric_bitstream.cpp | 102 ++++++++++++++++++ .../src/fpga_bitstream/fabric_bitstream.cpp | 26 ++++- .../src/fpga_bitstream/fabric_bitstream.h | 20 +++- 3 files changed, 141 insertions(+), 7 deletions(-) diff --git a/openfpga/src/fpga_bitstream/build_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/build_fabric_bitstream.cpp index f281a72dc..1be2025b3 100644 --- a/openfpga/src/fpga_bitstream/build_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_fabric_bitstream.cpp @@ -15,6 +15,7 @@ #include "openfpga_reserved_words.h" #include "openfpga_naming.h" +#include "decoder_library_utils.h" #include "bitstream_manager_utils.h" #include "build_fabric_bitstream.h" @@ -73,6 +74,90 @@ void rec_build_module_fabric_dependent_chain_bitstream(const BitstreamManager& b } } +/******************************************************************** + * This function aims to build a bitstream for memory-bank protocol + * It will walk through all the configurable children under a module + * in a recursive way, following a Depth-First Search (DFS) strategy + * For each configuration child, we use its instance name as a key to spot the + * configuration bits in bitstream manager. + * Note that it is guarentee that the instance name in module manager is + * consistent with the block names in bitstream manager + * We use this link to reorganize the bitstream in the sequence of memories as we stored + * in the configurable_children() and configurable_child_instances() of each module of module manager + * + * In such configuration organization, each memory cell has an unique index. + * Using this index, we can infer the address codes for both BL and WL decoders. + * Note that, we must get the number of BLs and WLs before using this function! + *******************************************************************/ +static +void rec_build_module_fabric_dependent_memory_bank_bitstream(const BitstreamManager& bitstream_manager, + const ConfigBlockId& parent_block, + const ModuleManager& module_manager, + const ModuleId& parent_module, + const size_t& bl_addr_size, + const size_t& wl_addr_size, + const size_t& num_bls, + const size_t& num_wls, + size_t& cur_mem_index, + FabricBitstream& fabric_bitstream) { + + /* Depth-first search: if we have any children in the parent_block, + * we dive to the next level first! + */ + if (0 < bitstream_manager.block_children(parent_block).size()) { + for (size_t child_id = 0; child_id < module_manager.configurable_children(parent_module).size(); ++child_id) { + ModuleId child_module = module_manager.configurable_children(parent_module)[child_id]; + size_t child_instance = module_manager.configurable_child_instances(parent_module)[child_id]; + /* Get the instance name and ensure it is not empty */ + std::string instance_name = module_manager.instance_name(parent_module, child_module, child_instance); + + /* Find the child block that matches the instance name! */ + ConfigBlockId child_block = bitstream_manager.find_child_block(parent_block, instance_name); + /* We must have one valid block id! */ + if (true != bitstream_manager.valid_block_id(child_block)) + VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block)); + + /* Go recursively */ + rec_build_module_fabric_dependent_memory_bank_bitstream(bitstream_manager, child_block, + module_manager, child_module, + bl_addr_size, wl_addr_size, + num_bls, num_wls, + cur_mem_index, + fabric_bitstream); + } + /* Ensure that there should be no configuration bits in the parent block */ + VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size()); + } + + /* Note that, reach here, it means that this is a leaf node. + * We add the configuration bits to the fabric_bitstream, + * And then, we can return + */ + for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) { + FabricBitId fabric_bit = fabric_bitstream.add_bit(config_bit); + + /* Find BL address */ + size_t cur_bl_index = cur_mem_index / num_bls; + std::vector bl_addr_bits_vec = itobin_vec(cur_bl_index, bl_addr_size); + + /* Find WL address */ + size_t cur_wl_index = cur_mem_index % num_wls; + std::vector wl_addr_bits_vec = itobin_vec(cur_wl_index, wl_addr_size); + + /* Set BL address */ + fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec); + + /* Set WL address */ + fabric_bitstream.set_bit_wl_address(fabric_bit, wl_addr_bits_vec); + + /* Set data input */ + fabric_bitstream.set_bit_din(fabric_bit, bitstream_manager.bit_value(config_bit)); + + /* Increase the memory index */ + cur_mem_index++; + } +} + /******************************************************************** * This function aims to build a bitstream for frame-based configuration protocol * It will walk through all the configurable children under a module @@ -287,6 +372,23 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc break; } case CONFIG_MEM_MEMORY_BANK: { + size_t cur_mem_index = 0; + /* Find BL address port size */ + ModulePortId bl_addr_port = module_manager.find_module_port(top_module, std::string(MEMORY_BL_PORT_NAME)); + BasicPort bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port); + size_t num_bls = find_memory_decoder_data_size(bl_addr_port_info.get_width()); + + /* Find WL address port size */ + ModulePortId wl_addr_port = module_manager.find_module_port(top_module, std::string(MEMORY_WL_PORT_NAME)); + BasicPort wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port); + size_t num_wls = find_memory_decoder_data_size(wl_addr_port_info.get_width()); + + rec_build_module_fabric_dependent_memory_bank_bitstream(bitstream_manager, top_block, + module_manager, top_module, + bl_addr_port_info.get_width(), + wl_addr_port_info.get_width(), + num_bls, num_wls, + cur_mem_index, fabric_bitstream); break; } case CONFIG_MEM_FRAME_BASED: { diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp index 7306eba01..1e318a530 100644 --- a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp @@ -31,7 +31,18 @@ std::vector FabricBitstream::bit_address(const FabricBitId& bit_id) cons /* Ensure a valid id */ VTR_ASSERT(true == valid_bit_id(bit_id)); - return bit_addresses_[bit_id]; + return bit_addresses_[bit_id][0]; +} + +std::vector FabricBitstream::bit_bl_address(const FabricBitId& bit_id) const { + return bit_address(bit_id); +} + +std::vector FabricBitstream::bit_wl_address(const FabricBitId& bit_id) const { + /* Ensure a valid id */ + VTR_ASSERT(true == valid_bit_id(bit_id)); + + return bit_addresses_[bit_id][1]; } bool FabricBitstream::bit_din(const FabricBitId& bit_id) const { @@ -58,7 +69,18 @@ FabricBitId FabricBitstream::add_bit(const ConfigBitId& config_bit_id) { void FabricBitstream::set_bit_address(const FabricBitId& bit_id, const std::vector& address) { VTR_ASSERT(true == valid_bit_id(bit_id)); - bit_addresses_[bit_id] = address; + bit_addresses_[bit_id][0] = address; +} + +void FabricBitstream::set_bit_bl_address(const FabricBitId& bit_id, + const std::vector& address) { + set_bit_address(bit_id, address); +} + +void FabricBitstream::set_bit_wl_address(const FabricBitId& bit_id, + const std::vector& address) { + VTR_ASSERT(true == valid_bit_id(bit_id)); + bit_addresses_[bit_id][1] = address; } void FabricBitstream::set_bit_din(const FabricBitId& bit_id, diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream.h b/openfpga/src/fpga_bitstream/fabric_bitstream.h index 12d1c7885..519330dae 100644 --- a/openfpga/src/fpga_bitstream/fabric_bitstream.h +++ b/openfpga/src/fpga_bitstream/fabric_bitstream.h @@ -13,11 +13,11 @@ * By using the link between ArchBitstreamManager and FabricBitstream, * we can build a sequence of configuration bits to fit different configuration protocols. * - * +----------------------+ +--------------------------+ - * | | ConfigBitId | | + * +----------------------+ +-------------------+ + * | | ConfigBitId | | * | ArchBitstreamManager |---------------->| FabricBitstream | - * | | | | - * +----------------------+ +--------------------------+ + * | | | | + * +----------------------+ +-------------------+ * * Restrictions: * 1. Each block inside BitstreamManager should have only 1 parent block @@ -53,6 +53,8 @@ class FabricBitstream { /* Find the address of bitstream */ std::vector bit_address(const FabricBitId& bit_id) const; + std::vector bit_bl_address(const FabricBitId& bit_id) const; + std::vector bit_wl_address(const FabricBitId& bit_id) const; /* Find the data-in of bitstream */ bool bit_din(const FabricBitId& bit_id) const; @@ -64,6 +66,12 @@ class FabricBitstream { void set_bit_address(const FabricBitId& bit_id, const std::vector& address); + void set_bit_bl_address(const FabricBitId& bit_id, + const std::vector& address); + + void set_bit_wl_address(const FabricBitId& bit_id, + const std::vector& address); + void set_bit_din(const FabricBitId& bit_id, const bool& din); @@ -83,8 +91,10 @@ class FabricBitstream { /* Address bits: this is designed for memory decoders * Here we store the binary format of the address, which can be loaded * to the configuration protocol directly + * + * We use a 2-element array, as we may have a BL address and a WL address */ - vtr::vector> bit_addresses_; + vtr::vector, 2>> bit_addresses_; /* Data input (Din) bits: this is designed for memory decoders */ vtr::vector bit_dins_;