From 76d58ebaa0177169006f55d96897363e2bf80f34 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Oct 2021 21:48:10 -0700 Subject: [PATCH] [FPGA-Verilog] Move clock generator to generic stimuli and shift register clock period is auto tuned by programming clock period --- .../fpga_verilog/verilog_top_testbench.cpp | 16 +- .../verilog_top_testbench_memory_bank.cpp | 161 ++++++++++++------ .../verilog_top_testbench_memory_bank.h | 16 +- 3 files changed, 128 insertions(+), 65 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index 0ef3eebcb..3a09db525 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -1112,21 +1112,30 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp, *******************************************************************/ static void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& fp, - const e_config_protocol_type& config_protocol_type, + const ConfigProtocol& config_protocol, const ModuleManager& module_manager, const ModuleId& top_module, + const bool& fast_configuration, + const bool& bit_value_to_skip, + const FabricBitstream& fabric_bitstream, const float& prog_clock_period, const float& timescale) { /* Validate the file stream */ valid_file_stream(fp); /* Branch on the type of configuration protocol */ - switch (config_protocol_type) { + switch (config_protocol.type()) { case CONFIG_MEM_STANDALONE: break; case CONFIG_MEM_SCAN_CHAIN: break; case CONFIG_MEM_QL_MEMORY_BANK: + print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(fp, + config_protocol, + module_manager,top_module, + fast_configuration, bit_value_to_skip, fabric_bitstream, + prog_clock_period, timescale); + break; case CONFIG_MEM_MEMORY_BANK: case CONFIG_MEM_FRAME_BASED: { ModulePortId en_port_id = module_manager.find_module_port(top_module, @@ -1956,8 +1965,9 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, /* Generate stimuli for programming interface */ print_verilog_top_testbench_configuration_protocol_stimulus(fp, - config_protocol.type(), + config_protocol, module_manager, top_module, + fast_configuration, bit_value_to_skip, fabric_bitstream, prog_clock_period, VERILOG_SIM_TIMESCALE); diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index 346f3b34b..607ad9d0e 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -87,9 +87,13 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, /* BL Shift register clock and registers */ BasicPort sr_clock_port(std::string(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME), 1); - fp << generate_verilog_port(VERILOG_PORT_WIRE, sr_clock_port) << ";" << std::endl; - BasicPort sr_clock_register_port(std::string(std::string(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1); - fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_register_port) << ";" << std::endl; + fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_port) << ";" << std::endl; + + /* Register to enable/disable bl/wl shift register clocks */ + BasicPort start_bl_sr_port(TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME, 1); + fp << generate_verilog_port(VERILOG_PORT_REG, start_bl_sr_port) << ";" << std::endl; + /* Register to count bl/wl shift register clocks */ + fp << "integer " << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME << ";" << std::endl; } /* Print the address port for the Word-Line decoder here */ @@ -125,9 +129,13 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, /* WL Shift register clock and registers */ BasicPort sr_clock_port(std::string(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME), 1); - fp << generate_verilog_port(VERILOG_PORT_WIRE, sr_clock_port) << ";" << std::endl; - BasicPort sr_clock_register_port(std::string(std::string(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1); - fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_register_port) << ";" << std::endl; + fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_port) << ";" << std::endl; + + /* Register to enable/disable bl/wl shift register clocks */ + BasicPort start_wl_sr_port(TOP_TB_START_WL_SHIFT_REGISTER_PORT_NAME, 1); + fp << generate_verilog_port(VERILOG_PORT_REG, start_wl_sr_port) << ";" << std::endl; + /* Register to count bl/wl shift register clocks */ + fp << "integer " << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME << ";" << std::endl; } /* Print the data-input port: only available when BL has a decoder */ @@ -191,6 +199,94 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, fp << ";" << std::endl; } +/** + * @brief Generate the Verilog codes for a shift register clocks that controls BL/WL protocols + */ +static +void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(std::fstream& fp, + const BasicPort& prog_clock_port, + const BasicPort& start_sr_port, + const BasicPort& sr_clock_port, + const float& sr_clock_period) { + /* Validate the file stream */ + valid_file_stream(fp); + + fp << "always"; + fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")"; + fp << " begin"; + fp << std::endl; + + fp << "\t"; + fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); + fp << ";" << std::endl; + + fp << "\t"; + fp << "while (" << generate_verilog_port(VERILOG_PORT_CONKT, start_sr_port) << ") begin"; + fp << std::endl; + + fp << "\t\t"; + fp << "#" << sr_clock_period << " "; + print_verilog_register_connection(fp, sr_clock_port, sr_clock_port, true); + + fp << "\t"; + fp << "end"; + fp << std::endl; + + fp << "\t"; + fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); + fp << ";" << std::endl; +} + +void print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(std::fstream& fp, + const ConfigProtocol& config_protocol, + const ModuleManager& module_manager, + const ModuleId& top_module, + const bool& fast_configuration, + const bool& bit_value_to_skip, + const FabricBitstream& fabric_bitstream, + const float& prog_clock_period, + const float& timescale) { + ModulePortId en_port_id = module_manager.find_module_port(top_module, + std::string(DECODER_ENABLE_PORT_NAME)); + BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1); + if (en_port_id) { + en_port = module_manager.module_port(top_module, en_port_id); + } + BasicPort en_register_port(std::string(en_port.get_name() + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1); + print_verilog_comment(fp, std::string("---- Generate enable signal waveform -----")); + print_verilog_shifted_clock_stimuli(fp, en_register_port, + 0.25 * prog_clock_period / timescale, + 0.5 * prog_clock_period / timescale, 0); + + /* Stimulus only for shift-register-based BL/WL protocols */ + BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX), 1); + BasicPort bl_sr_clock_port(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1); + BasicPort wl_sr_clock_port(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1); + BasicPort start_bl_sr_port(TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME, 1); + BasicPort start_wl_sr_port(TOP_TB_START_WL_SHIFT_REGISTER_PORT_NAME, 1); + + /* Reorganize the fabric bitstream by the same address across regions */ + if (CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()) { + MemoryBankShiftRegisterFabricBitstream fabric_bits_by_addr = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream, + fast_configuration, + bit_value_to_skip); + + /* TODO: Consider auto-tuned clock period for now */ + float bl_sr_clock_period = prog_clock_period / fabric_bits_by_addr.bl_width() / timescale; + float wl_sr_clock_period = prog_clock_period / fabric_bits_by_addr.wl_width() / timescale; + + if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) { + print_verilog_comment(fp, "----- BL Shift register clock generator -----"); + print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, prog_clock_port, start_bl_sr_port, bl_sr_clock_port, 0.5 * bl_sr_clock_period); + } + + if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()) { + print_verilog_comment(fp, "----- WL Shift register clock generator -----"); + print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, prog_clock_port, start_wl_sr_port, wl_sr_clock_port, 0.5 * wl_sr_clock_period); + } + } +} + /* Verilog codes to load bitstream from a bit file for memory bank using flatten BL/WLs */ static void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& fp, @@ -326,40 +422,6 @@ void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----"); } -/* Verilog codes to load bitstream from a bit file for memory bank using flatten BL/WLs */ -void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(std::fstream& fp, - const BasicPort& prog_clock_port, - const BasicPort& start_sr_port, - const BasicPort& sr_clock_port) { - /* Validate the file stream */ - valid_file_stream(fp); - - fp << "always"; - fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")"; - fp << " begin"; - fp << std::endl; - - fp << "\t"; - fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); - fp << ";" << std::endl; - - fp << "\t"; - fp << "while (" << generate_verilog_port(VERILOG_PORT_CONKT, start_sr_port) << ") begin"; - fp << std::endl; - - fp << "\t\t"; - fp << "#0.05 "; - print_verilog_register_connection(fp, sr_clock_port, sr_clock_port, true); - - fp << "\t"; - fp << "end"; - fp << std::endl; - - fp << "\t"; - fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); - fp << ";" << std::endl; -} - /* Verilog codes to load bitstream from a bit file for memory bank using flatten BL/WLs */ static void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::fstream& fp, @@ -429,16 +491,6 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f fp << "reg [$clog2(`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE << "):0] " << TOP_TB_BITSTREAM_INDEX_REG_NAME << ";" << std::endl; - /* Register to enable/disable bl/wl shift register clocks */ - BasicPort start_bl_sr_port(TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME, 1); - fp << generate_verilog_port(VERILOG_PORT_REG, start_bl_sr_port) << ";" << std::endl; - BasicPort start_wl_sr_port(TOP_TB_START_WL_SHIFT_REGISTER_PORT_NAME, 1); - fp << generate_verilog_port(VERILOG_PORT_REG, start_wl_sr_port) << ";" << std::endl; - - /* Register to count bl/wl shift register clocks */ - fp << "integer " << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME << ";" << std::endl; - fp << "integer " << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME << ";" << std::endl; - print_verilog_comment(fp, "----- Preload bitstream file to a virtual memory -----"); fp << "initial begin" << std::endl; fp << "\t"; @@ -462,6 +514,9 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f fp << ";"; fp << std::endl; + BasicPort start_bl_sr_port(TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME, 1); + BasicPort start_wl_sr_port(TOP_TB_START_WL_SHIFT_REGISTER_PORT_NAME, 1); + fp << "\t"; fp << generate_verilog_port_constant_values(start_bl_sr_port, std::vector(start_bl_sr_port.get_width(), 0), true); fp << ";"; @@ -480,12 +535,6 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f BasicPort bl_sr_clock_port(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1); BasicPort wl_sr_clock_port(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1); - print_verilog_comment(fp, "----- BL Shift register clock generator -----"); - print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, prog_clock_port, start_bl_sr_port, bl_sr_clock_port); - - print_verilog_comment(fp, "----- WL Shift register clock generator -----"); - print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, prog_clock_port, start_wl_sr_port, wl_sr_clock_port); - print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----"); fp << "always"; fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")"; diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h index 194f0b86f..78e364a4c 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h @@ -35,13 +35,17 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, const ConfigProtocol& config_protocol); /** - * @brief Generate the Verilog codes for a shift register clocks that controls BL/WL protocols + * @brief Generate the Verilog codes that generate stimuli waveforms for BL/WL protocols */ -void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(std::fstream& fp, - const BasicPort& prog_clock_port, - const BasicPort& start_sr_port, - const BasicPort& sr_clock_port); - +void print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(std::fstream& fp, + const ConfigProtocol& config_protocol, + const ModuleManager& module_manager, + const ModuleId& top_module, + const bool& fast_configuration, + const bool& bit_value_to_skip, + const FabricBitstream& fabric_bitstream, + const float& prog_clock_period, + const float& timescale); /** * @brief Print stimulus for a FPGA fabric with a memory bank configuration protocol