[Tool] Support region-based bitstream in fabric bitstream data base and Verilog testbenches
This commit is contained in:
parent
180d72f3e5
commit
e988e35f81
|
@ -38,13 +38,38 @@ static
|
||||||
void rec_build_module_fabric_dependent_chain_bitstream(const BitstreamManager& bitstream_manager,
|
void rec_build_module_fabric_dependent_chain_bitstream(const BitstreamManager& bitstream_manager,
|
||||||
const ConfigBlockId& parent_block,
|
const ConfigBlockId& parent_block,
|
||||||
const ModuleManager& module_manager,
|
const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
const ModuleId& parent_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,
|
/* Depth-first search: if we have any children in the parent_block,
|
||||||
* we dive to the next level first!
|
* we dive to the next level first!
|
||||||
*/
|
*/
|
||||||
if (0 < bitstream_manager.block_children(parent_block).size()) {
|
if (0 < bitstream_manager.block_children(parent_block).size()) {
|
||||||
|
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));
|
||||||
|
|
||||||
|
/* 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) {
|
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];
|
ModuleId child_module = module_manager.configurable_children(parent_module)[child_id];
|
||||||
size_t child_instance = module_manager.configurable_child_instances(parent_module)[child_id];
|
size_t child_instance = module_manager.configurable_child_instances(parent_module)[child_id];
|
||||||
|
@ -59,8 +84,12 @@ void rec_build_module_fabric_dependent_chain_bitstream(const BitstreamManager& b
|
||||||
|
|
||||||
/* Go recursively */
|
/* Go recursively */
|
||||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, child_block,
|
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, child_block,
|
||||||
module_manager, child_module,
|
module_manager, top_module,
|
||||||
fabric_bitstream);
|
child_module,
|
||||||
|
config_region,
|
||||||
|
fabric_bitstream,
|
||||||
|
fabric_bitstream_region);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Ensure that there should be no configuration bits in the parent block */
|
/* Ensure that there should be no configuration bits in the parent block */
|
||||||
VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
|
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
|
* And then, we can return
|
||||||
*/
|
*/
|
||||||
for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) {
|
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 */
|
/* Reserve bits before build-up */
|
||||||
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
||||||
|
|
||||||
|
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,
|
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
|
||||||
module_manager, top_module,
|
module_manager, top_module,
|
||||||
fabric_bitstream);
|
top_module,
|
||||||
|
config_region,
|
||||||
|
fabric_bitstream,
|
||||||
|
fabric_bitstream_region);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CONFIG_MEM_SCAN_CHAIN: {
|
case CONFIG_MEM_SCAN_CHAIN: {
|
||||||
/* Reserve bits before build-up */
|
/* Reserve bits before build-up */
|
||||||
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
||||||
|
|
||||||
|
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,
|
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
|
||||||
module_manager, top_module,
|
module_manager, top_module,
|
||||||
fabric_bitstream);
|
top_module,
|
||||||
fabric_bitstream.reverse();
|
config_region,
|
||||||
|
fabric_bitstream,
|
||||||
|
fabric_bitstream_region);
|
||||||
|
fabric_bitstream.reverse_region_bits(fabric_bitstream_region);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CONFIG_MEM_MEMORY_BANK: {
|
case CONFIG_MEM_MEMORY_BANK: {
|
||||||
|
|
|
@ -50,7 +50,7 @@ std::vector<FabricBitId> FabricBitstream::region_bits(const FabricBitRegionId& r
|
||||||
/* Ensure a valid id */
|
/* Ensure a valid id */
|
||||||
VTR_ASSERT(true == valid_region_id(region_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) {
|
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() {
|
void FabricBitstream::reverse() {
|
||||||
|
@ -204,7 +221,7 @@ void FabricBitstream::reverse() {
|
||||||
void FabricBitstream::reverse_region_bits(const FabricBitRegionId& region_id) {
|
void FabricBitstream::reverse_region_bits(const FabricBitRegionId& region_id) {
|
||||||
VTR_ASSERT(true == valid_region_id(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 */
|
/* Reserve regions */
|
||||||
void reserve_regions(const size_t& num_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 */
|
/* Reserve bits by region */
|
||||||
void reverse_region_bits(const FabricBitRegionId& region_id);
|
void reverse_region_bits(const FabricBitRegionId& region_id);
|
||||||
|
|
||||||
|
@ -182,7 +188,7 @@ class FabricBitstream {
|
||||||
/* Unique id of a region in the Bitstream */
|
/* Unique id of a region in the Bitstream */
|
||||||
size_t num_regions_;
|
size_t num_regions_;
|
||||||
std::unordered_set<FabricBitRegionId> invalid_region_ids_;
|
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 */
|
/* Unique id of a bit in the Bitstream */
|
||||||
size_t num_bits_;
|
size_t num_bits_;
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include "simulation_utils.h"
|
#include "simulation_utils.h"
|
||||||
#include "openfpga_atom_netlist_utils.h"
|
#include "openfpga_atom_netlist_utils.h"
|
||||||
|
|
||||||
|
#include "fabric_bitstream_utils.h"
|
||||||
|
|
||||||
#include "verilog_constants.h"
|
#include "verilog_constants.h"
|
||||||
#include "verilog_writer_utils.h"
|
#include "verilog_writer_utils.h"
|
||||||
#include "verilog_testbench_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
|
* Print local wires for configuration chain protocols
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static
|
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 */
|
/* Validate the file stream */
|
||||||
valid_file_stream(fp);
|
valid_file_stream(fp);
|
||||||
|
|
||||||
/* Print the head of configuraion-chains here */
|
/* Print the head of configuraion-chains here */
|
||||||
print_verilog_comment(fp, std::string("---- Configuration-chain head -----"));
|
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;
|
fp << generate_verilog_port(VERILOG_PORT_REG, config_chain_head_port) << ";" << std::endl;
|
||||||
|
|
||||||
/* Print the tail of configuration-chains here */
|
/* Print the tail of configuration-chains here */
|
||||||
print_verilog_comment(fp, std::string("---- Configuration-chain tail -----"));
|
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;
|
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);
|
print_verilog_top_testbench_flatten_memory_port(fp, module_manager, top_module);
|
||||||
break;
|
break;
|
||||||
case CONFIG_MEM_SCAN_CHAIN:
|
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;
|
break;
|
||||||
case CONFIG_MEM_MEMORY_BANK:
|
case CONFIG_MEM_MEMORY_BANK:
|
||||||
print_verilog_top_testbench_memory_bank_port(fp, module_manager, top_module);
|
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 bool& bit_value_to_skip,
|
||||||
const BitstreamManager& bitstream_manager,
|
const BitstreamManager& bitstream_manager,
|
||||||
const FabricBitstream& fabric_bitstream) {
|
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 */
|
/* Branch on the type of configuration protocol */
|
||||||
switch (sram_orgz_type) {
|
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;
|
num_config_clock_cycles = 2;
|
||||||
break;
|
break;
|
||||||
case CONFIG_MEM_SCAN_CHAIN:
|
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) {
|
if (true == fast_configuration) {
|
||||||
size_t full_num_config_clock_cycles = num_config_clock_cycles;
|
/* For fast configuration, the number of bits to be skipped
|
||||||
size_t num_bits_to_skip = 0;
|
* depends on each regional bitstream
|
||||||
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
|
* For example:
|
||||||
if (bit_value_to_skip != bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id))) {
|
* Region 0: 000000001111101010
|
||||||
break;
|
* Region 1: 00000011010101
|
||||||
}
|
* Region 2: 0010101111000110
|
||||||
num_bits_to_skip++;
|
* 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",
|
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,
|
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;
|
break;
|
||||||
case CONFIG_MEM_MEMORY_BANK:
|
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
|
* During each programming cycle, we feed the input of scan chain with a memory bit
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static
|
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 */
|
/* Validate the file stream */
|
||||||
valid_file_stream(fp);
|
valid_file_stream(fp);
|
||||||
|
|
||||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||||
BasicPort cc_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 cc_head_value(generate_configuration_chain_head_name() + std::string("_val"), 1);
|
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 */
|
/* Add an empty line as splitter */
|
||||||
fp << std::endl;
|
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 */
|
/* No need to have a specific task. Loading is done in 1 clock cycle */
|
||||||
break;
|
break;
|
||||||
case CONFIG_MEM_SCAN_CHAIN:
|
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;
|
break;
|
||||||
case CONFIG_MEM_MEMORY_BANK:
|
case CONFIG_MEM_MEMORY_BANK:
|
||||||
print_verilog_top_testbench_load_bitstream_task_memory_bank(fp,
|
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,
|
void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
||||||
const bool& fast_configuration,
|
const bool& fast_configuration,
|
||||||
const bool& bit_value_to_skip,
|
const bool& bit_value_to_skip,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
const BitstreamManager& bitstream_manager,
|
const BitstreamManager& bitstream_manager,
|
||||||
const FabricBitstream& fabric_bitstream) {
|
const FabricBitstream& fabric_bitstream) {
|
||||||
/* Validate the file stream */
|
/* 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
|
* We do not care the value of scan_chain head during the first programming cycle
|
||||||
* It is reset anyway
|
* 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);
|
std::vector<size_t> initial_values(config_chain_head_port.get_width(), 0);
|
||||||
|
|
||||||
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
|
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;
|
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'
|
/* 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)
|
* 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 (size_t ibit = num_bits_to_skip; ibit < regional_bitstream_max_size; ++ibit) {
|
||||||
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
|
std::vector<size_t> curr_cc_head_val;
|
||||||
if ( (false == start_config)
|
curr_cc_head_val.reserve(fabric_bitstream.regions().size());
|
||||||
&& (bit_value_to_skip != bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id)))) {
|
for (const auto& region_bitstream : regional_bitstreams) {
|
||||||
start_config = true;
|
curr_cc_head_val.push_back((size_t)region_bitstream[ibit]);
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
|
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 */
|
/* 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:
|
case CONFIG_MEM_SCAN_CHAIN:
|
||||||
print_verilog_top_testbench_configuration_chain_bitstream(fp, fast_configuration,
|
print_verilog_top_testbench_configuration_chain_bitstream(fp, fast_configuration,
|
||||||
bit_value_to_skip,
|
bit_value_to_skip,
|
||||||
|
module_manager, top_module,
|
||||||
bitstream_manager, fabric_bitstream);
|
bitstream_manager, fabric_bitstream);
|
||||||
break;
|
break;
|
||||||
case CONFIG_MEM_MEMORY_BANK:
|
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