[Tool] Support external bitstream file when generating full testbench for frame-based decoder
This commit is contained in:
parent
618b04568f
commit
d644b8f22d
|
@ -215,15 +215,48 @@ int write_memory_bank_fabric_bitstream_to_text_file(std::fstream& fp,
|
|||
*******************************************************************/
|
||||
static
|
||||
int write_frame_based_fabric_bitstream_to_text_file(std::fstream& fp,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
int status = 0;
|
||||
|
||||
FrameFabricBitstream fabric_bits_by_addr = build_frame_based_fabric_bitstream_by_address(fabric_bitstream);
|
||||
|
||||
/* The address sizes and data input sizes are the same across any element,
|
||||
* just get it from the 1st element to save runtime
|
||||
*/
|
||||
size_t addr_size = fabric_bits_by_addr.begin()->first.size();
|
||||
size_t din_size = fabric_bits_by_addr.begin()->second.size();
|
||||
|
||||
/* Identify and output bitstream size information */
|
||||
size_t num_bits_to_skip = 0;
|
||||
if (true == fast_configuration) {
|
||||
num_bits_to_skip = find_frame_based_fast_configuration_fabric_bitstream_size(fabric_bitstream, bit_value_to_skip);
|
||||
VTR_ASSERT(num_bits_to_skip < fabric_bits_by_addr.size());
|
||||
VTR_LOG("Fast configuration will skip %g% (%lu/%lu) of configuration bitstream.\n",
|
||||
100. * (float) num_bits_to_skip / (float) fabric_bits_by_addr.size(),
|
||||
num_bits_to_skip, fabric_bits_by_addr.size());
|
||||
}
|
||||
|
||||
/* Output information about how to intepret the bitstream */
|
||||
fp << "// Bitstream length: " << fabric_bits_by_addr.size() - num_bits_to_skip << std::endl;
|
||||
fp << "// Bitstream address size (LSB -> MSB): " << addr_size << std::endl;
|
||||
fp << "// Bitstream data input size (LSB -> MSB): " << din_size << std::endl;
|
||||
|
||||
for (const auto& addr_din_pair : fabric_bits_by_addr) {
|
||||
/* When fast configuration is enabled,
|
||||
* the rule to skip any configuration bit should consider the whole data input values.
|
||||
* Only all the bits in the din port match the value to be skipped,
|
||||
* the programming cycle can be skipped!
|
||||
*/
|
||||
if (true == fast_configuration) {
|
||||
if (addr_din_pair.second == std::vector<bool>(addr_din_pair.second.size(), bit_value_to_skip)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write address code */
|
||||
fp << addr_din_pair.first;
|
||||
fp << " ";
|
||||
|
||||
/* Write data input */
|
||||
for (const bool& din_value : addr_din_pair.second) {
|
||||
|
@ -306,6 +339,8 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage
|
|||
break;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
status = write_frame_based_fabric_bitstream_to_text_file(fp,
|
||||
apply_fast_configuration,
|
||||
bit_value_to_skip,
|
||||
fabric_bitstream);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -2122,6 +2122,128 @@ void print_verilog_full_testbench_configuration_chain_bitstream(std::fstream& fp
|
|||
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print stimulus for a FPGA fabric with a frame-based configuration protocol
|
||||
* where configuration bits are programming in serial (one by one)
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_full_testbench_frame_decoder_bitstream(std::fstream& fp,
|
||||
const std::string& bitstream_file,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* Reorganize the fabric bitstream by the same address across regions */
|
||||
FrameFabricBitstream fabric_bits_by_addr = build_frame_based_fabric_bitstream_by_address(fabric_bitstream);
|
||||
|
||||
/* For fast configuration, identify the final bitstream size to be used */
|
||||
size_t num_bits_to_skip = 0;
|
||||
if (true == fast_configuration) {
|
||||
num_bits_to_skip = find_frame_based_fast_configuration_fabric_bitstream_size(fabric_bitstream, bit_value_to_skip);
|
||||
}
|
||||
VTR_ASSERT(num_bits_to_skip < fabric_bits_by_addr.size());
|
||||
|
||||
/* Feed address and data input pair one by one
|
||||
* Note: the first cycle is reserved for programming reset
|
||||
* We should give dummy values
|
||||
*/
|
||||
ModulePortId addr_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_ADDRESS_PORT_NAME));
|
||||
BasicPort addr_port = module_manager.module_port(top_module, addr_port_id);
|
||||
std::vector<size_t> initial_addr_values(addr_port.get_width(), 0);
|
||||
|
||||
ModulePortId din_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_DATA_IN_PORT_NAME));
|
||||
BasicPort din_port = module_manager.module_port(top_module, din_port_id);
|
||||
std::vector<size_t> initial_din_values(din_port.get_width(), 0);
|
||||
|
||||
/* Define a constant for the bitstream length */
|
||||
print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_LENGTH_VARIABLE), fabric_bits_by_addr.size() - num_bits_to_skip);
|
||||
print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_WIDTH_VARIABLE), addr_port.get_width() + din_port.get_width());
|
||||
|
||||
/* Declare local variables for bitstream loading in Verilog */
|
||||
print_verilog_comment(fp, "----- Virtual memory to store the bitstream from external file -----");
|
||||
fp << "reg [0:`" << TOP_TB_BITSTREAM_WIDTH_VARIABLE << " - 1] ";
|
||||
fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "[0:`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE << " - 1];";
|
||||
fp << std::endl;
|
||||
|
||||
fp << "reg [$clog2(`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE << ") - 1:0] " << TOP_TB_BITSTREAM_INDEX_REG_NAME << ";" << std::endl;
|
||||
|
||||
print_verilog_comment(fp, "----- Preload bitstream file to a virtual memory -----");
|
||||
fp << "initial begin" << std::endl;
|
||||
fp << "\t";
|
||||
fp << "$readmemb(\"" << bitstream_file << "\", " << TOP_TB_BITSTREAM_MEM_REG_NAME << ");";
|
||||
fp << std::endl;
|
||||
|
||||
print_verilog_comment(fp, "----- Address port default input -----");
|
||||
fp << "\t";
|
||||
fp << generate_verilog_port_constant_values(addr_port, initial_addr_values);
|
||||
fp << ";";
|
||||
fp << std::endl;
|
||||
|
||||
print_verilog_comment(fp, "----- Data-input port default input -----");
|
||||
fp << "\t";
|
||||
fp << generate_verilog_port_constant_values(din_port, initial_din_values);
|
||||
fp << ";";
|
||||
fp << std::endl;
|
||||
|
||||
fp << "end";
|
||||
fp << std::endl;
|
||||
|
||||
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX), 1);
|
||||
fp << "always";
|
||||
fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")";
|
||||
fp << " begin";
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\t";
|
||||
fp << "if (";
|
||||
fp << TOP_TB_BITSTREAM_INDEX_REG_NAME;
|
||||
fp << " >= ";
|
||||
fp << "`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE;
|
||||
fp << ") begin";
|
||||
fp << std::endl;
|
||||
|
||||
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
|
||||
fp << "\t\t";
|
||||
std::vector<size_t> config_done_final_values(config_done_port.get_width(), 1);
|
||||
fp << generate_verilog_port_constant_values(config_done_port, config_done_final_values, true);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << "\t";
|
||||
fp << "end else begin";
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\t\t";
|
||||
fp << "{";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
|
||||
fp << ", ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, din_port);
|
||||
fp << "}";
|
||||
fp << " <= ";
|
||||
fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "[" << TOP_TB_BITSTREAM_INDEX_REG_NAME << "]";
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << "\t\t";
|
||||
fp << TOP_TB_BITSTREAM_INDEX_REG_NAME;
|
||||
fp << " <= ";
|
||||
fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << " + 1";
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << "\t";
|
||||
fp << "end";
|
||||
fp << std::endl;
|
||||
|
||||
fp << "end";
|
||||
fp << std::endl;
|
||||
|
||||
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Generate the stimuli for the full testbench
|
||||
|
@ -2155,6 +2277,12 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp,
|
|||
case CONFIG_MEM_MEMORY_BANK:
|
||||
break;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
print_verilog_full_testbench_frame_decoder_bitstream(fp, bitstream_file,
|
||||
fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
|
||||
break;
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
|
|
Loading…
Reference in New Issue