Merge pull request #325 from lnis-uofu/testbench_external_bitstream
Support flatten configuration protocol in bitstream writer and full testbench that reads external bitstream file
This commit is contained in:
commit
72f2742846
|
@ -40,65 +40,6 @@ void write_fabric_bitstream_text_file_head(std::fstream& fp) {
|
||||||
fp << "// Date: " << std::ctime(&end_time);
|
fp << "// Date: " << std::ctime(&end_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* Write a configuration bit into a plain text file
|
|
||||||
* The format depends on the type of configuration protocol
|
|
||||||
* - Vanilla (standalone): just put down pure 0|1 bitstream
|
|
||||||
* - Configuration chain: just put down pure 0|1 bitstream
|
|
||||||
* - Memory bank : <BL address> <WL address> <bit>
|
|
||||||
* - Frame-based configuration protocol : <address> <bit>
|
|
||||||
*
|
|
||||||
* Return:
|
|
||||||
* - 0 if succeed
|
|
||||||
* - 1 if critical errors occured
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
int write_fabric_config_bit_to_text_file(std::fstream& fp,
|
|
||||||
const BitstreamManager& bitstream_manager,
|
|
||||||
const FabricBitstream& fabric_bitstream,
|
|
||||||
const FabricBitId& fabric_bit,
|
|
||||||
const e_config_protocol_type& config_type) {
|
|
||||||
if (false == valid_file_stream(fp)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (config_type) {
|
|
||||||
case CONFIG_MEM_STANDALONE:
|
|
||||||
case CONFIG_MEM_SCAN_CHAIN:
|
|
||||||
fp << bitstream_manager.bit_value(fabric_bitstream.config_bit(fabric_bit));
|
|
||||||
break;
|
|
||||||
case CONFIG_MEM_MEMORY_BANK: {
|
|
||||||
for (const char& addr_bit : fabric_bitstream.bit_bl_address(fabric_bit)) {
|
|
||||||
fp << addr_bit;
|
|
||||||
}
|
|
||||||
write_space_to_file(fp, 1);
|
|
||||||
for (const char& addr_bit : fabric_bitstream.bit_wl_address(fabric_bit)) {
|
|
||||||
fp << addr_bit;
|
|
||||||
}
|
|
||||||
write_space_to_file(fp, 1);
|
|
||||||
fp << bitstream_manager.bit_value(fabric_bitstream.config_bit(fabric_bit));
|
|
||||||
fp << "\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CONFIG_MEM_FRAME_BASED: {
|
|
||||||
for (const char& addr_bit : fabric_bitstream.bit_address(fabric_bit)) {
|
|
||||||
fp << addr_bit;
|
|
||||||
}
|
|
||||||
write_space_to_file(fp, 1);
|
|
||||||
fp << bitstream_manager.bit_value(fabric_bitstream.config_bit(fabric_bit));
|
|
||||||
fp << "\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
|
||||||
"Invalid configuration protocol type!\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Write the flatten fabric bitstream to a plain text file
|
* Write the flatten fabric bitstream to a plain text file
|
||||||
*
|
*
|
||||||
|
@ -109,20 +50,20 @@ int write_fabric_config_bit_to_text_file(std::fstream& fp,
|
||||||
static
|
static
|
||||||
int write_flatten_fabric_bitstream_to_text_file(std::fstream& fp,
|
int write_flatten_fabric_bitstream_to_text_file(std::fstream& fp,
|
||||||
const BitstreamManager& bitstream_manager,
|
const BitstreamManager& bitstream_manager,
|
||||||
const FabricBitstream& fabric_bitstream,
|
const FabricBitstream& fabric_bitstream) {
|
||||||
const ConfigProtocol& config_protocol) {
|
if (false == valid_file_stream(fp)) {
|
||||||
int status = 0;
|
return 1;
|
||||||
for (const FabricBitId& fabric_bit : fabric_bitstream.bits()) {
|
|
||||||
status = write_fabric_config_bit_to_text_file(fp, bitstream_manager,
|
|
||||||
fabric_bitstream,
|
|
||||||
fabric_bit,
|
|
||||||
config_protocol.type());
|
|
||||||
if (1 == status) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
/* Output bitstream size information */
|
||||||
|
fp << "// Bitstream length: " << fabric_bitstream.num_bits() << std::endl;
|
||||||
|
|
||||||
|
/* Output bitstream data */
|
||||||
|
for (const FabricBitId& fabric_bit : fabric_bitstream.bits()) {
|
||||||
|
fp << bitstream_manager.bit_value(fabric_bitstream.config_bit(fabric_bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -356,8 +297,7 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage
|
||||||
case CONFIG_MEM_STANDALONE:
|
case CONFIG_MEM_STANDALONE:
|
||||||
status = write_flatten_fabric_bitstream_to_text_file(fp,
|
status = write_flatten_fabric_bitstream_to_text_file(fp,
|
||||||
bitstream_manager,
|
bitstream_manager,
|
||||||
fabric_bitstream,
|
fabric_bitstream);
|
||||||
config_protocol);
|
|
||||||
break;
|
break;
|
||||||
case CONFIG_MEM_SCAN_CHAIN:
|
case CONFIG_MEM_SCAN_CHAIN:
|
||||||
status = write_config_chain_fabric_bitstream_to_text_file(fp,
|
status = write_config_chain_fabric_bitstream_to_text_file(fp,
|
||||||
|
|
|
@ -1937,6 +1937,101 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Print stimulus for a FPGA fabric with a flatten memory (standalone) configuration protocol
|
||||||
|
* We will load the bitstream in the second clock cycle, right after the first reset cycle
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void print_verilog_full_testbench_vanilla_bitstream(std::fstream& fp,
|
||||||
|
const std::string& bitstream_file,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const FabricBitstream& fabric_bitstream) {
|
||||||
|
/* Validate the file stream */
|
||||||
|
valid_file_stream(fp);
|
||||||
|
|
||||||
|
/* Find Bit-Line and Word-Line port */
|
||||||
|
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||||
|
|
||||||
|
/* Find Bit-Line and Word-Line port */
|
||||||
|
ModulePortId bl_port_id = module_manager.find_module_port(top_module, std::string(MEMORY_BL_PORT_NAME));
|
||||||
|
BasicPort bl_port = module_manager.module_port(top_module, bl_port_id);
|
||||||
|
|
||||||
|
ModulePortId wl_port_id = module_manager.find_module_port(top_module, std::string(MEMORY_WL_PORT_NAME));
|
||||||
|
BasicPort wl_port = module_manager.module_port(top_module, wl_port_id);
|
||||||
|
|
||||||
|
/* Define a constant for the bitstream length */
|
||||||
|
print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_LENGTH_VARIABLE), fabric_bitstream.num_bits());
|
||||||
|
|
||||||
|
/* 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_LENGTH_VARIABLE << " - 1] ";
|
||||||
|
fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "[0:0];";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
/* Initial value should be the first configuration bits
|
||||||
|
* In the rest of programming cycles,
|
||||||
|
* configuration bits are fed at the falling edge of programming clock.
|
||||||
|
* We do not care the value of scan_chain head during the first programming cycle
|
||||||
|
* It is reset anyway
|
||||||
|
*/
|
||||||
|
std::vector<size_t> initial_bl_values(bl_port.get_width(), 0);
|
||||||
|
std::vector<size_t> initial_wl_values(wl_port.get_width(), 0);
|
||||||
|
|
||||||
|
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
|
||||||
|
fp << "initial" << std::endl;
|
||||||
|
fp << "\tbegin" << std::endl;
|
||||||
|
print_verilog_comment(fp, "----- Configuration chain default input -----");
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << generate_verilog_port_constant_values(bl_port, initial_bl_values);
|
||||||
|
fp << ";" << std::endl;
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << generate_verilog_port_constant_values(wl_port, initial_wl_values);
|
||||||
|
fp << ";" << std::endl;
|
||||||
|
|
||||||
|
print_verilog_comment(fp, "----- Preload bitstream file to a virtual memory -----");
|
||||||
|
fp << "\t";
|
||||||
|
fp << "$readmemb(\"" << bitstream_file << "\", " << TOP_TB_BITSTREAM_MEM_REG_NAME << ");";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ") begin" << std::endl;
|
||||||
|
|
||||||
|
/* Enable all the WLs */
|
||||||
|
std::vector<size_t> enabled_wl_values(wl_port.get_width(), 1);
|
||||||
|
fp << "\t\t\t";
|
||||||
|
fp << generate_verilog_port_constant_values(wl_port, enabled_wl_values);
|
||||||
|
fp << ";" << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t\t";
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_CONKT, bl_port);
|
||||||
|
fp << " <= ";
|
||||||
|
fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "[0]";
|
||||||
|
fp << ";" << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\tend" << std::endl;
|
||||||
|
|
||||||
|
/* Disable all the WLs */
|
||||||
|
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t\t";
|
||||||
|
fp << generate_verilog_port_constant_values(wl_port, initial_wl_values);
|
||||||
|
fp << ";" << std::endl;
|
||||||
|
|
||||||
|
/* Raise the flag of configuration done when bitstream loading is complete */
|
||||||
|
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||||
|
|
||||||
|
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
|
||||||
|
fp << "\t\t\t";
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
|
||||||
|
fp << " <= ";
|
||||||
|
std::vector<size_t> config_done_enable_values(config_done_port.get_width(), 1);
|
||||||
|
fp << generate_verilog_constant_values(config_done_enable_values);
|
||||||
|
fp << ";" << std::endl;
|
||||||
|
|
||||||
|
fp << "\tend" << std::endl;
|
||||||
|
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Print stimulus for a FPGA fabric with a configuration chain protocol
|
* Print stimulus for a FPGA fabric with a configuration chain protocol
|
||||||
* where configuration bits are programming in serial (one by one)
|
* where configuration bits are programming in serial (one by one)
|
||||||
|
@ -2411,6 +2506,12 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp,
|
||||||
/* Branch on the type of configuration protocol */
|
/* Branch on the type of configuration protocol */
|
||||||
switch (config_protocol_type) {
|
switch (config_protocol_type) {
|
||||||
case CONFIG_MEM_STANDALONE:
|
case CONFIG_MEM_STANDALONE:
|
||||||
|
print_verilog_full_testbench_vanilla_bitstream(fp,
|
||||||
|
bitstream_file,
|
||||||
|
module_manager,
|
||||||
|
top_module,
|
||||||
|
fabric_bitstream);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case CONFIG_MEM_SCAN_CHAIN:
|
case CONFIG_MEM_SCAN_CHAIN:
|
||||||
print_verilog_full_testbench_configuration_chain_bitstream(fp, bitstream_file,
|
print_verilog_full_testbench_configuration_chain_bitstream(fp, bitstream_file,
|
||||||
|
@ -2962,11 +3063,6 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
|
||||||
netlist_annotation,
|
netlist_annotation,
|
||||||
explicit_port_mapping);
|
explicit_port_mapping);
|
||||||
|
|
||||||
/* Print tasks used for loading bitstreams */
|
|
||||||
print_verilog_top_testbench_load_bitstream_task(fp,
|
|
||||||
config_protocol.type(),
|
|
||||||
module_manager, top_module);
|
|
||||||
|
|
||||||
/* load bitstream to FPGA fabric in a configuration phase */
|
/* load bitstream to FPGA fabric in a configuration phase */
|
||||||
print_verilog_full_testbench_bitstream(fp,
|
print_verilog_full_testbench_bitstream(fp,
|
||||||
bitstream_file,
|
bitstream_file,
|
||||||
|
|
|
@ -16,9 +16,11 @@ timeout_each_job = 20*60
|
||||||
fpga_flow=yosys_vpr
|
fpga_flow=yosys_vpr
|
||||||
|
|
||||||
[OpenFPGA_SHELL]
|
[OpenFPGA_SHELL]
|
||||||
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/full_testbench_example_script.openfpga
|
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/write_full_testbench_example_script.openfpga
|
||||||
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_standalone_openfpga.xml
|
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_standalone_openfpga.xml
|
||||||
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
||||||
|
openfpga_vpr_device_layout=
|
||||||
|
openfpga_fast_configuration=
|
||||||
|
|
||||||
[ARCHITECTURES]
|
[ARCHITECTURES]
|
||||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||||
|
|
Loading…
Reference in New Issue