openfpga/src/fpga_bitstream/build_fabric_bitstream.cpp
/********************************************************************
 * 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!
 *******************************************************************/
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!
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& top_module,
                                                             const ModuleId& parent_module,
                                                             const ConfigRegionId& config_region,
                                                             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,
                                                             const FabricBitRegionId& fabric_bitstream_region) {
  if (0 < bitstream_manager.block_children(parent_block).size()) {
    if (parent_module == top_module) {
      std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(parent_module, config_region);
      VTR_ASSERT(2 <= configurable_children.size()); 
      size_t num_configurable_children = configurable_children.size() - 2;
      if (0 == num_configurable_children) {
        VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
        return;
      }
      for (size_t child_id = 0; child_id < num_configurable_children; ++child_id) {
        ModuleId child_module = configurable_children[child_id]; 
        size_t child_instance = module_manager.region_configurable_child_instances(parent_module, config_region)[child_id]; 
        std::string instance_name = module_manager.instance_name(parent_module, child_module, child_instance);
        ConfigBlockId child_block = bitstream_manager.find_child_block(parent_block, instance_name); 
        VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block));
        rec_build_module_fabric_dependent_memory_bank_bitstream(bitstream_manager, child_block,
                                                                module_manager, top_module, child_module,
                                                                config_region,
                                                                bl_addr_size, wl_addr_size,
                                                                num_bls, num_wls,
                                                                cur_mem_index,
                                                                fabric_bitstream,
                                                                fabric_bitstream_region);
      }
    } else {
      VTR_ASSERT(parent_module != top_module);
      std::vector<ModuleId> configurable_children = module_manager.configurable_children(parent_module);
      size_t num_configurable_children = configurable_children.size();
      if (0 == num_configurable_children) {
        VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
        return;
      }
      for (size_t child_id = 0; child_id < num_configurable_children; ++child_id) {
        ModuleId child_module = configurable_children[child_id]; 
        size_t child_instance = module_manager.configurable_child_instances(parent_module)[child_id]; 
        std::string instance_name = module_manager.instance_name(parent_module, child_module, child_instance);
        ConfigBlockId child_block = bitstream_manager.find_child_block(parent_block, instance_name); 
        VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block));
        rec_build_module_fabric_dependent_memory_bank_bitstream(bitstream_manager, child_block,
                                                                module_manager, top_module, child_module,
                                                                config_region,
                                                                bl_addr_size, wl_addr_size,
                                                                num_bls, num_wls,
                                                                cur_mem_index,
                                                                fabric_bitstream,
                                                                fabric_bitstream_region);
      }
    }
    VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
    return;
  }
  for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) {
    FabricBitId fabric_bit = fabric_bitstream.add_bit(config_bit);
    size_t cur_bl_index = std::floor(cur_mem_index / num_bls);
    std::vector<char> bl_addr_bits_vec = itobin_charvec(cur_bl_index, bl_addr_size);
    size_t cur_wl_index = cur_mem_index % num_wls;
    std::vector<char> wl_addr_bits_vec = itobin_charvec(cur_wl_index, wl_addr_size);
    fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec);
    fabric_bitstream.set_bit_wl_address(fabric_bit, wl_addr_bits_vec);
    fabric_bitstream.set_bit_din(fabric_bit, bitstream_manager.bit_value(config_bit));
    fabric_bitstream.add_bit_to_region(fabric_bitstream_region, fabric_bit);
    cur_mem_index++;
  }
}
static void rec_build_module_fabric_dependent_memory_bank_bitstream ( const BitstreamManager & bitstream_manager , const ConfigBlockId & parent_block , const ModuleManager & module_manager , const ModuleId & top_module , const ModuleId & parent_module , const ConfigRegionId & config_region , 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 , const FabricBitRegionId & fabric_bitstream_region ) { if ( 0 < bitstream_manager . block_children ( parent_block ) . size ( ) ) { if ( parent_module == top_module ) { std :: vector < ModuleId > configurable_children = module_manager . region_configurable_children ( parent_module , config_region ) ; VTR_ASSERT ( 2 <= configurable_children . size ( ) ) ; size_t num_configurable_children = configurable_children . size ( ) - 2 ; if ( 0 == num_configurable_children ) { VTR_ASSERT ( 0 == bitstream_manager . block_bits ( parent_block ) . size ( ) ) ; return ; } for ( size_t child_id = 0 ; child_id < num_configurable_children ; ++ child_id ) { ModuleId child_module = configurable_children [ child_id ] ; size_t child_instance = module_manager . region_configurable_child_instances ( parent_module , config_region ) [ child_id ] ; std :: string instance_name = module_manager . instance_name ( parent_module , child_module , child_instance ) ; ConfigBlockId child_block = bitstream_manager . find_child_block ( parent_block , instance_name ) ; VTR_ASSERT ( true == bitstream_manager . valid_block_id ( child_block ) ) ; rec_build_module_fabric_dependent_memory_bank_bitstream ( bitstream_manager , child_block , module_manager , top_module , child_module , config_region , bl_addr_size , wl_addr_size , num_bls , num_wls , cur_mem_index , fabric_bitstream , fabric_bitstream_region ) ; } } else { VTR_ASSERT ( parent_module != top_module ) ; std :: vector < ModuleId > configurable_children = module_manager . configurable_children ( parent_module ) ; size_t num_configurable_children = configurable_children . size ( ) ; if ( 0 == num_configurable_children ) { VTR_ASSERT ( 0 == bitstream_manager . block_bits ( parent_block ) . size ( ) ) ; return ; } for ( size_t child_id = 0 ; child_id < num_configurable_children ; ++ child_id ) { ModuleId child_module = configurable_children [ child_id ] ; size_t child_instance = module_manager . configurable_child_instances ( parent_module ) [ child_id ] ; std :: string instance_name = module_manager . instance_name ( parent_module , child_module , child_instance ) ; ConfigBlockId child_block = bitstream_manager . find_child_block ( parent_block , instance_name ) ; VTR_ASSERT ( true == bitstream_manager . valid_block_id ( child_block ) ) ; rec_build_module_fabric_dependent_memory_bank_bitstream ( bitstream_manager , child_block , module_manager , top_module , child_module , config_region , bl_addr_size , wl_addr_size , num_bls , num_wls , cur_mem_index , fabric_bitstream , fabric_bitstream_region ) ; } } VTR_ASSERT ( 0 == bitstream_manager . block_bits ( parent_block ) . size ( ) ) ; return ; } for ( const ConfigBitId & config_bit : bitstream_manager . block_bits ( parent_block ) ) { FabricBitId fabric_bit = fabric_bitstream . add_bit ( config_bit ) ; size_t cur_bl_index = std :: floor ( cur_mem_index / num_bls ) ; std :: vector < char > bl_addr_bits_vec = itobin_charvec ( cur_bl_index , bl_addr_size ) ; size_t cur_wl_index = cur_mem_index % num_wls ; std :: vector < char > wl_addr_bits_vec = itobin_charvec ( cur_wl_index , wl_addr_size ) ; fabric_bitstream . set_bit_bl_address ( fabric_bit , bl_addr_bits_vec ) ; fabric_bitstream . set_bit_wl_address ( fabric_bit , wl_addr_bits_vec ) ; fabric_bitstream . set_bit_din ( fabric_bit , bitstream_manager . bit_value ( config_bit ) ) ; fabric_bitstream . add_bit_to_region ( fabric_bitstream_region , fabric_bit ) ; cur_mem_index ++ ; } }
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.
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 .
/* Depth-first search: if we have any children in the parent_block, 
   * we dive to the next level first! 
   */ /* For top module:
     *   - Use regional configurable children
     *   - we will skip the two decoders at the end of the configurable children list
     */ /* Early exit if there is no configurable children */ /* Ensure that there should be no configuration bits in the parent block */ /* Get the instance name and ensure it is not empty */ /* Find the child block that matches the instance name! */ /* We must have one valid block id! */ /* Go recursively */ /* For other modules:
       *   - Use configurable children directly
       *   - no need to exclude decoders as they are not there
       */ /* Early exit if there is no configurable children */ /* Ensure that there should be no configuration bits in the parent block */ /* Get the instance name and ensure it is not empty */ /* Find the child block that matches the instance name! */ /* We must have one valid block id! */ /* Go recursively */ /* Ensure that there should be no configuration bits in the parent block */ /* 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
   */ /* Find BL address */ /* Find WL address */ /* Set BL address */ /* Set WL address */ /* Set data input */ /* Add the bit to the region */ /* Increase the memory index */