From 366dcff75d15ffc90b360383741ff691c6da2b03 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 7 Jun 2021 21:49:31 -0600 Subject: [PATCH] [Tool] Now 'write_full_testbench' supports flatten(vanilla) configuration protocol --- .../write_text_fabric_bitstream.cpp | 86 +++------------ .../fpga_verilog/verilog_top_testbench.cpp | 101 ++++++++++++++++++ 2 files changed, 114 insertions(+), 73 deletions(-) diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index fdd27f649..5338d7b09 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -40,65 +40,6 @@ void write_fabric_bitstream_text_file_head(std::fstream& fp) { 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 : - * - Frame-based configuration protocol :
- * - * 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 * @@ -109,20 +50,20 @@ int write_fabric_config_bit_to_text_file(std::fstream& fp, static int write_flatten_fabric_bitstream_to_text_file(std::fstream& fp, const BitstreamManager& bitstream_manager, - const FabricBitstream& fabric_bitstream, - const ConfigProtocol& config_protocol) { - int status = 0; - 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; - } + const FabricBitstream& fabric_bitstream) { + if (false == valid_file_stream(fp)) { + return 1; } - 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: status = write_flatten_fabric_bitstream_to_text_file(fp, bitstream_manager, - fabric_bitstream, - config_protocol); + fabric_bitstream); break; case CONFIG_MEM_SCAN_CHAIN: status = write_config_chain_fabric_bitstream_to_text_file(fp, diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index 6534d5cd6..c138a3bd9 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -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 initial_bl_values(bl_port.get_width(), 0); + std::vector 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 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 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 * 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 */ switch (config_protocol_type) { case CONFIG_MEM_STANDALONE: + print_verilog_full_testbench_vanilla_bitstream(fp, + bitstream_file, + module_manager, + top_module, + fabric_bitstream); + break; case CONFIG_MEM_SCAN_CHAIN: print_verilog_full_testbench_configuration_chain_bitstream(fp, bitstream_file,