[Tool] Support region-based bitstream in fabric bitstream data base and Verilog testbenches
This commit is contained in:
parent
180d72f3e5
commit
e988e35f81
|
@ -38,29 +38,58 @@ static
|
|||
void rec_build_module_fabric_dependent_chain_bitstream(const BitstreamManager& bitstream_manager,
|
||||
const ConfigBlockId& parent_block,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const ModuleId& parent_module,
|
||||
FabricBitstream& fabric_bitstream) {
|
||||
const ConfigRegionId& config_region,
|
||||
FabricBitstream& fabric_bitstream,
|
||||
const FabricBitRegionId& fabric_bitstream_region) {
|
||||
|
||||
/* 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);
|
||||
if (parent_module == top_module) {
|
||||
for (size_t child_id = 0; child_id < module_manager.region_configurable_children(parent_module, config_region).size(); ++child_id) {
|
||||
ModuleId child_module = module_manager.region_configurable_children(parent_module, config_region)[child_id];
|
||||
size_t child_instance = module_manager.region_configurable_child_instances(parent_module, config_region)[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));
|
||||
/* 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_chain_bitstream(bitstream_manager, child_block,
|
||||
module_manager, child_module,
|
||||
fabric_bitstream);
|
||||
/* Go recursively */
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, child_block,
|
||||
module_manager, top_module,
|
||||
child_module,
|
||||
config_region,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
} else {
|
||||
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_chain_bitstream(bitstream_manager, child_block,
|
||||
module_manager, top_module,
|
||||
child_module,
|
||||
config_region,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
}
|
||||
/* Ensure that there should be no configuration bits in the parent block */
|
||||
VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
|
||||
|
@ -71,7 +100,8 @@ void rec_build_module_fabric_dependent_chain_bitstream(const BitstreamManager& b
|
|||
* And then, we can return
|
||||
*/
|
||||
for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) {
|
||||
fabric_bitstream.add_bit(config_bit);
|
||||
FabricBitId fabric_bit = fabric_bitstream.add_bit(config_bit);
|
||||
fabric_bitstream.add_bit_to_region(fabric_bitstream_region, fabric_bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -382,19 +412,32 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
/* Reserve bits before build-up */
|
||||
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
||||
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region();
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module,
|
||||
top_module,
|
||||
config_region,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_SCAN_CHAIN: {
|
||||
/* Reserve bits before build-up */
|
||||
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
||||
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
fabric_bitstream.reverse();
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region();
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module,
|
||||
top_module,
|
||||
config_region,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
fabric_bitstream.reverse_region_bits(fabric_bitstream_region);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_MEMORY_BANK: {
|
||||
|
|
|
@ -50,7 +50,7 @@ std::vector<FabricBitId> FabricBitstream::region_bits(const FabricBitRegionId& r
|
|||
/* Ensure a valid id */
|
||||
VTR_ASSERT(true == valid_region_id(region_id));
|
||||
|
||||
return region_bits_[region_id];
|
||||
return region_bit_ids_[region_id];
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -185,7 +185,24 @@ void FabricBitstream::set_wl_address_length(const size_t& length) {
|
|||
}
|
||||
|
||||
void FabricBitstream::reserve_regions(const size_t& num_regions) {
|
||||
region_bits_.reserve(num_regions);
|
||||
region_bit_ids_.reserve(num_regions);
|
||||
}
|
||||
|
||||
FabricBitRegionId FabricBitstream::add_region() {
|
||||
FabricBitRegionId region = FabricBitRegionId(num_regions_);
|
||||
/* Add a new bit, and allocate associated data structures */
|
||||
num_regions_++;
|
||||
region_bit_ids_.emplace_back();
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
void FabricBitstream::add_bit_to_region(const FabricBitRegionId& region_id,
|
||||
const FabricBitId& bit_id) {
|
||||
VTR_ASSERT(true == valid_region_id(region_id));
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
|
||||
region_bit_ids_[region_id].push_back(bit_id);
|
||||
}
|
||||
|
||||
void FabricBitstream::reverse() {
|
||||
|
@ -204,7 +221,7 @@ void FabricBitstream::reverse() {
|
|||
void FabricBitstream::reverse_region_bits(const FabricBitRegionId& region_id) {
|
||||
VTR_ASSERT(true == valid_region_id(region_id));
|
||||
|
||||
std::reverse(region_bits_[region_id].begin(), region_bits_[region_id].end());
|
||||
std::reverse(region_bit_ids_[region_id].begin(), region_bit_ids_[region_id].end());
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -149,6 +149,12 @@ class FabricBitstream {
|
|||
/* Reserve regions */
|
||||
void reserve_regions(const size_t& num_regions);
|
||||
|
||||
/* Add a new configuration region */
|
||||
FabricBitRegionId add_region();
|
||||
|
||||
void add_bit_to_region(const FabricBitRegionId& region_id,
|
||||
const FabricBitId& bit_id);
|
||||
|
||||
/* Reserve bits by region */
|
||||
void reverse_region_bits(const FabricBitRegionId& region_id);
|
||||
|
||||
|
@ -182,7 +188,7 @@ class FabricBitstream {
|
|||
/* Unique id of a region in the Bitstream */
|
||||
size_t num_regions_;
|
||||
std::unordered_set<FabricBitRegionId> invalid_region_ids_;
|
||||
vtr::vector<FabricBitRegionId, std::vector<FabricBitId>> region_bits_;
|
||||
vtr::vector<FabricBitRegionId, std::vector<FabricBitId>> region_bit_ids_;
|
||||
|
||||
/* Unique id of a bit in the Bitstream */
|
||||
size_t num_bits_;
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "simulation_utils.h"
|
||||
#include "openfpga_atom_netlist_utils.h"
|
||||
|
||||
#include "fabric_bitstream_utils.h"
|
||||
|
||||
#include "verilog_constants.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_testbench_utils.h"
|
||||
|
@ -136,18 +138,22 @@ void print_verilog_top_testbench_flatten_memory_port(std::fstream& fp,
|
|||
* Print local wires for configuration chain protocols
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_config_chain_port(std::fstream& fp) {
|
||||
void print_verilog_top_testbench_config_chain_port(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* Print the head of configuraion-chains here */
|
||||
print_verilog_comment(fp, std::string("---- Configuration-chain head -----"));
|
||||
BasicPort config_chain_head_port(generate_configuration_chain_head_name(), 1);
|
||||
ModulePortId cc_head_port_id = module_manager.find_module_port(top_module, generate_configuration_chain_head_name());
|
||||
BasicPort config_chain_head_port = module_manager.module_port(top_module, cc_head_port_id);
|
||||
fp << generate_verilog_port(VERILOG_PORT_REG, config_chain_head_port) << ";" << std::endl;
|
||||
|
||||
/* Print the tail of configuration-chains here */
|
||||
print_verilog_comment(fp, std::string("---- Configuration-chain tail -----"));
|
||||
BasicPort config_chain_tail_port(generate_configuration_chain_tail_name(), 1);
|
||||
ModulePortId cc_tail_port_id = module_manager.find_module_port(top_module, generate_configuration_chain_tail_name());
|
||||
BasicPort config_chain_tail_port = module_manager.module_port(top_module, cc_tail_port_id);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, config_chain_tail_port) << ";" << std::endl;
|
||||
}
|
||||
|
||||
|
@ -271,7 +277,7 @@ void print_verilog_top_testbench_config_protocol_port(std::fstream& fp,
|
|||
print_verilog_top_testbench_flatten_memory_port(fp, module_manager, top_module);
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
print_verilog_top_testbench_config_chain_port(fp);
|
||||
print_verilog_top_testbench_config_chain_port(fp, module_manager, top_module);
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
print_verilog_top_testbench_memory_bank_port(fp, module_manager, top_module);
|
||||
|
@ -659,7 +665,10 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
|
|||
const bool& bit_value_to_skip,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
size_t num_config_clock_cycles = 1 + fabric_bitstream.num_bits();
|
||||
/* Find the longest regional bitstream */
|
||||
size_t regional_bitstream_max_size = find_fabric_regional_bitstream_max_size(fabric_bitstream);
|
||||
|
||||
size_t num_config_clock_cycles = 1 + regional_bitstream_max_size;
|
||||
|
||||
/* Branch on the type of configuration protocol */
|
||||
switch (sram_orgz_type) {
|
||||
|
@ -670,23 +679,24 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
|
|||
num_config_clock_cycles = 2;
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
/* For fast configuraiton, the bitstream size counts from the first bit '1' */
|
||||
/* For fast configuration, the bitstream size counts from the first bit '1' */
|
||||
if (true == fast_configuration) {
|
||||
size_t full_num_config_clock_cycles = num_config_clock_cycles;
|
||||
size_t num_bits_to_skip = 0;
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
|
||||
if (bit_value_to_skip != bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id))) {
|
||||
break;
|
||||
}
|
||||
num_bits_to_skip++;
|
||||
}
|
||||
/* For fast configuration, the number of bits to be skipped
|
||||
* depends on each regional bitstream
|
||||
* For example:
|
||||
* Region 0: 000000001111101010
|
||||
* Region 1: 00000011010101
|
||||
* Region 2: 0010101111000110
|
||||
* The number of bits that can be skipped is limited by Region 2
|
||||
*/
|
||||
size_t num_bits_to_skip = find_configuration_chain_fabric_bitstream_size_to_be_skipped(fabric_bitstream, bitstream_manager, bit_value_to_skip);
|
||||
|
||||
num_config_clock_cycles = full_num_config_clock_cycles - num_bits_to_skip;
|
||||
num_config_clock_cycles = 1 + regional_bitstream_max_size - num_bits_to_skip;
|
||||
|
||||
VTR_LOG("Fast configuration reduces number of configuration clock cycles from %lu to %lu (compression_rate = %f%)\n",
|
||||
full_num_config_clock_cycles,
|
||||
1 + regional_bitstream_max_size,
|
||||
num_config_clock_cycles,
|
||||
100. * ((float)num_config_clock_cycles / (float)full_num_config_clock_cycles - 1.));
|
||||
100. * ((float)num_config_clock_cycles / (float)(1 + regional_bitstream_max_size) - 1.));
|
||||
}
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
|
@ -770,14 +780,17 @@ void print_verilog_top_testbench_benchmark_instance(std::fstream& fp,
|
|||
* During each programming cycle, we feed the input of scan chain with a memory bit
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fstream& fp) {
|
||||
void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||
BasicPort cc_head_port(generate_configuration_chain_head_name(), 1);
|
||||
BasicPort cc_head_value(generate_configuration_chain_head_name() + std::string("_val"), 1);
|
||||
ModulePortId cc_head_port_id = module_manager.find_module_port(top_module, generate_configuration_chain_head_name());
|
||||
BasicPort cc_head_port = module_manager.module_port(top_module, cc_head_port_id);
|
||||
BasicPort cc_head_value(generate_configuration_chain_head_name() + std::string("_val"), cc_head_port.get_width());
|
||||
|
||||
/* Add an empty line as splitter */
|
||||
fp << std::endl;
|
||||
|
@ -962,7 +975,9 @@ void print_verilog_top_testbench_load_bitstream_task(std::fstream& fp,
|
|||
/* No need to have a specific task. Loading is done in 1 clock cycle */
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
print_verilog_top_testbench_load_bitstream_task_configuration_chain(fp);
|
||||
print_verilog_top_testbench_load_bitstream_task_configuration_chain(fp,
|
||||
module_manager,
|
||||
top_module);
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
print_verilog_top_testbench_load_bitstream_task_memory_bank(fp,
|
||||
|
@ -1359,6 +1374,8 @@ static
|
|||
void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
/* Validate the file stream */
|
||||
|
@ -1370,7 +1387,8 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
|||
* We do not care the value of scan_chain head during the first programming cycle
|
||||
* It is reset anyway
|
||||
*/
|
||||
BasicPort config_chain_head_port(generate_configuration_chain_head_name(), 1);
|
||||
ModulePortId cc_head_port_id = module_manager.find_module_port(top_module, generate_configuration_chain_head_name());
|
||||
BasicPort config_chain_head_port = module_manager.module_port(top_module, cc_head_port_id);
|
||||
std::vector<size_t> initial_values(config_chain_head_port.get_width(), 0);
|
||||
|
||||
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
|
||||
|
@ -1383,27 +1401,60 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
|||
|
||||
fp << std::endl;
|
||||
|
||||
/* Find the longest bitstream */
|
||||
size_t regional_bitstream_max_size = find_fabric_regional_bitstream_max_size(fabric_bitstream);
|
||||
|
||||
/* For fast configuration, the bitstream size counts from the first bit '1' */
|
||||
size_t num_bits_to_skip = 0;
|
||||
if (true == fast_configuration) {
|
||||
num_bits_to_skip = find_configuration_chain_fabric_bitstream_size_to_be_skipped(fabric_bitstream, bitstream_manager, bit_value_to_skip);
|
||||
}
|
||||
VTR_ASSERT(num_bits_to_skip < regional_bitstream_max_size);
|
||||
|
||||
/* Reorganize the regional bitstreams to be the same size */
|
||||
std::vector<std::vector<bool>> regional_bitstreams;
|
||||
regional_bitstreams.reserve(fabric_bitstream.regions().size());
|
||||
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
|
||||
std::vector<bool> curr_regional_bitstream;
|
||||
curr_regional_bitstream.resize(regional_bitstream_max_size, false);
|
||||
/* Starting index should consider the offset between the current bitstream size and
|
||||
* the maximum size of regional bitstream
|
||||
*/
|
||||
size_t offset = regional_bitstream_max_size - fabric_bitstream.region_bits(region).size();
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) {
|
||||
curr_regional_bitstream[offset] = bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id));
|
||||
offset++;
|
||||
}
|
||||
VTR_ASSERT(offset == regional_bitstream_max_size);
|
||||
|
||||
/* Add the adapt sub-bitstream */
|
||||
regional_bitstreams.push_back(curr_regional_bitstream);
|
||||
}
|
||||
|
||||
/* Attention: when the fast configuration is enabled, we will start from the first bit '1'
|
||||
* This requires a reset signal (as we forced in the first clock cycle)
|
||||
*
|
||||
* Note that bitstream may come from different regions
|
||||
* The bitstream value to be loaded should be organized as follows
|
||||
*
|
||||
* cycleA
|
||||
* |
|
||||
* Region 0: 0|00000001111101010
|
||||
* Region 1: | 00000011010101
|
||||
* Region 2: | 0010101111000110
|
||||
*
|
||||
* Zero bits will be added to the head of those bitstreams are shorter
|
||||
* than the longest bitstream
|
||||
*/
|
||||
bool start_config = false;
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
|
||||
if ( (false == start_config)
|
||||
&& (bit_value_to_skip != bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id)))) {
|
||||
start_config = true;
|
||||
}
|
||||
|
||||
/* In fast configuration mode, we do not output anything
|
||||
* until we have to (the first bit '1' detected)
|
||||
*/
|
||||
if ( (true == fast_configuration)
|
||||
&& (false == start_config)) {
|
||||
continue;
|
||||
for (size_t ibit = num_bits_to_skip; ibit < regional_bitstream_max_size; ++ibit) {
|
||||
std::vector<size_t> curr_cc_head_val;
|
||||
curr_cc_head_val.reserve(fabric_bitstream.regions().size());
|
||||
for (const auto& region_bitstream : regional_bitstreams) {
|
||||
curr_cc_head_val.push_back((size_t)region_bitstream[ibit]);
|
||||
}
|
||||
|
||||
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
|
||||
fp << "(1'b" << (size_t)bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id)) << ");" << std::endl;
|
||||
fp << "(" << generate_verilog_constant_values(curr_cc_head_val) << ");" << std::endl;
|
||||
}
|
||||
|
||||
/* Raise the flag of configuration done when bitstream loading is complete */
|
||||
|
@ -1654,6 +1705,7 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp,
|
|||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
print_verilog_top_testbench_configuration_chain_bitstream(fp, fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
bitstream_manager, fabric_bitstream);
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/************************************************************************
|
||||
* Function to perform fundamental operation for fabric bitstream class
|
||||
* These functions are not universal methods for the FabricBitstream class
|
||||
* They are made to ease the development in some specific purposes
|
||||
* Please classify such functions in this file
|
||||
***********************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "fabric_bitstream_utils.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* Find the longest bitstream size of a fabric bitstream
|
||||
*******************************************************************/
|
||||
size_t find_fabric_regional_bitstream_max_size(const FabricBitstream& fabric_bitstream) {
|
||||
size_t regional_bitstream_max_size = 0;
|
||||
/* Find the longest regional bitstream */
|
||||
for (const auto& region : fabric_bitstream.regions()) {
|
||||
if (regional_bitstream_max_size < fabric_bitstream.region_bits(region).size()) {
|
||||
regional_bitstream_max_size = fabric_bitstream.region_bits(region).size();
|
||||
}
|
||||
}
|
||||
return regional_bitstream_max_size;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* For fast configuration, the number of bits to be skipped
|
||||
* depends on each regional bitstream
|
||||
* For example:
|
||||
* Region 0: 000000001111101010
|
||||
* Region 1: 00000011010101
|
||||
* Region 2: 0010101111000110
|
||||
* The number of bits that can be skipped is limited by Region 2
|
||||
* Find the longest bitstream size of a fabric bitstream
|
||||
*******************************************************************/
|
||||
size_t find_configuration_chain_fabric_bitstream_size_to_be_skipped(const FabricBitstream& fabric_bitstream,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const bool& bit_value_to_skip) {
|
||||
size_t regional_bitstream_max_size = find_fabric_regional_bitstream_max_size(fabric_bitstream);
|
||||
|
||||
size_t num_bits_to_skip = size_t(-1);
|
||||
for (const auto& region : fabric_bitstream.regions()) {
|
||||
size_t curr_region_num_bits_to_skip = 0;
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) {
|
||||
if (bit_value_to_skip != bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id))) {
|
||||
break;
|
||||
}
|
||||
curr_region_num_bits_to_skip++;
|
||||
}
|
||||
/* For regional bitstream which is short than the longest region bitstream,
|
||||
* The number of bits to skip
|
||||
*/
|
||||
curr_region_num_bits_to_skip += regional_bitstream_max_size - fabric_bitstream.region_bits(region).size();
|
||||
num_bits_to_skip = std::min(curr_region_num_bits_to_skip, num_bits_to_skip);
|
||||
}
|
||||
|
||||
return num_bits_to_skip;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,29 @@
|
|||
/********************************************************************
|
||||
* Header file for fabric_bitstream_utils.cpp
|
||||
*******************************************************************/
|
||||
#ifndef FABRIC_BITSTREAM_UTILS_H
|
||||
#define FABRIC_BITSTREAM_UTILS_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <vector>
|
||||
#include "bitstream_manager.h"
|
||||
#include "fabric_bitstream.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
size_t find_fabric_regional_bitstream_max_size(const FabricBitstream& fabric_bitstream);
|
||||
|
||||
size_t find_configuration_chain_fabric_bitstream_size_to_be_skipped(const FabricBitstream& fabric_bitstream,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const bool& bit_value_to_skip);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue