diff --git a/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp b/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp index 66b4d1f23..c08aecb02 100644 --- a/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp +++ b/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp @@ -154,6 +154,13 @@ void BitstreamManager::reserve_blocks(const size_t& num_blocks) { child_block_ids_.reserve(num_blocks); } +void BitstreamManager::reserve_bits(const size_t& num_bits) { + bit_ids_.reserve(num_bits); + bit_values_.reserve(num_bits); + shared_config_bit_values_.reserve(num_bits); + bit_parent_block_ids_.reserve(num_bits); +} + ConfigBlockId BitstreamManager::create_block() { ConfigBlockId block = ConfigBlockId(block_ids_.size()); /* Add a new bit, and allocate associated data structures */ diff --git a/libopenfpga/libfpgabitstream/src/bitstream_manager.h b/libopenfpga/libfpgabitstream/src/bitstream_manager.h index 71bd63b43..c3a9372ee 100644 --- a/libopenfpga/libfpgabitstream/src/bitstream_manager.h +++ b/libopenfpga/libfpgabitstream/src/bitstream_manager.h @@ -98,6 +98,9 @@ class BitstreamManager { /* Reserve memory for a number of clocks */ void reserve_blocks(const size_t& num_blocks); + /* Reserve memory for a number of bits */ + void reserve_bits(const size_t& num_bits); + /* Create a new block of configuration bits */ ConfigBlockId create_block(); diff --git a/openfpga/src/fpga_bitstream/build_device_bitstream.cpp b/openfpga/src/fpga_bitstream/build_device_bitstream.cpp index 6d13dfe6f..59dd9c788 100644 --- a/openfpga/src/fpga_bitstream/build_device_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_device_bitstream.cpp @@ -20,6 +20,82 @@ /* begin namespace openfpga */ namespace openfpga { +/******************************************************************** + * Estimate the number of blocks to be added to the whole device bitstream + * This function will recursively walk through the module graph + * from the specified top module and count the number of configurable children + * which are the blocks that will be added to the bitstream manager + *******************************************************************/ +static +size_t rec_estimate_device_bitstream_num_blocks(const ModuleManager& module_manager, + const ModuleId& top_module) { + size_t num_blocks = 0; + + /* Those child modules which have no children are + * actually configurable memory elements + * We skip them in couting + */ + if (0 == module_manager.configurable_children(top_module).size()) { + return 0; + } + + size_t num_configurable_children = module_manager.configurable_children(top_module).size(); + for (size_t ichild = 0; ichild < num_configurable_children; ++ichild) { + ModuleId child_module = module_manager.configurable_children(top_module)[ichild]; + num_blocks += rec_estimate_device_bitstream_num_blocks(module_manager, child_module); + } + + /* Add the number of blocks at current level */ + num_blocks++; + + return num_blocks; +} + +/******************************************************************** + * Estimate the number of configuration bits to be added to the whole device bitstream + * This function will recursively walk through the module graph + * from the specified top module and count the number of leaf configurable children + * which are the bits that will be added to the bitstream manager + *******************************************************************/ +static +size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manager, + const ModuleId& top_module, + const e_config_protocol_type& config_protocol_type) { + size_t num_bits = 0; + + /* If a child module has no configurable children, this is a leaf node + * We can count it in. Otherwise, we should go recursively. + */ + if (0 == module_manager.configurable_children(top_module).size()) { + return 1; + } + + size_t num_configurable_children = module_manager.configurable_children(top_module).size(); + /* Frame-based configuration protocol will have 1 decoder + * if there are more than 1 configurable children + */ + if ( (CONFIG_MEM_FRAME_BASED == config_protocol_type) + && (2 <= num_configurable_children)) { + num_configurable_children--; + } + + /* Memory configuration protocol will have 2 decoders + * at the top-level + */ + if (CONFIG_MEM_MEMORY_BANK == config_protocol_type) { + std::string top_block_name = generate_fpga_top_module_name(); + if (top_module == module_manager.find_module(top_block_name)) { + num_configurable_children -= 2; + } + } + for (size_t ichild = 0; ichild < num_configurable_children; ++ichild) { + ModuleId child_module = module_manager.configurable_children(top_module)[ichild]; + num_bits += rec_estimate_device_bitstream_num_bits(module_manager, child_module, config_protocol_type); + } + + return num_bits; +} + /******************************************************************** * A top-level function to build a bistream from the FPGA device * 1. It will organize the bitstream w.r.t. the hierarchy of module graphs @@ -52,6 +128,21 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx, */ std::string top_block_name = generate_fpga_top_module_name(); ConfigBlockId top_block = bitstream_manager.add_block(top_block_name); + const ModuleId& top_module = openfpga_ctx.module_graph().find_module(top_block_name); + VTR_ASSERT(true == openfpga_ctx.module_graph().valid_module_id(top_module)); + + /* Estimate the number of blocks to be added to the database */ + size_t num_blocks_to_reserve = rec_estimate_device_bitstream_num_blocks(openfpga_ctx.module_graph(), + top_module); + bitstream_manager.reserve_blocks(num_blocks_to_reserve); + VTR_LOGV(verbose, "Reserved %lu configurable blocks\n", num_blocks_to_reserve); + + /* Estimate the number of bits to be added to the database */ + size_t num_bits_to_reserve = rec_estimate_device_bitstream_num_bits(openfpga_ctx.module_graph(), + top_module, + openfpga_ctx.arch().config_protocol.type()); + bitstream_manager.reserve_bits(num_bits_to_reserve); + VTR_LOGV(verbose, "Reserved %lu configuration bits\n", num_bits_to_reserve); /* Create bitstream from grids */ VTR_LOGV(verbose, "Building grid bitstream...\n"); @@ -80,7 +171,13 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx, openfpga_ctx.device_rr_gsb()); VTR_LOGV(verbose, "Done\n"); - VTR_LOGV(verbose, "Decoded %lu configuration bits\n", bitstream_manager.bits().size()); + VTR_LOGV(verbose, + "Decoded %lu configuration bits into %lu blocks\n", + bitstream_manager.bits().size(), + bitstream_manager.blocks().size()); + + //VTR_ASSERT(num_blocks_to_reserve == bitstream_manager.blocks().size()); + //VTR_ASSERT(num_bits_to_reserve == bitstream_manager.bits().size()); return bitstream_manager; }