From 82ed6b177b3405eee0f80d246046f886048a5980 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 6 Oct 2021 11:39:28 -0700 Subject: [PATCH] [FPGA-Verilog] Now consider clock constraints for BL/WL shift registers --- .../fpga_verilog/verilog_top_testbench.cpp | 53 +++++++----- .../verilog_top_testbench_memory_bank.cpp | 84 ++++++++++++++++--- .../verilog_top_testbench_memory_bank.h | 19 +++-- 3 files changed, 116 insertions(+), 40 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index f8477df5f..f45e84c9d 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -11,6 +11,9 @@ #include "vtr_assert.h" #include "vtr_time.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + /* Headers from openfpgautil library */ #include "openfpga_port.h" #include "openfpga_digest.h" @@ -1121,15 +1124,16 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp, * 1. the enable signal *******************************************************************/ static -void print_verilog_top_testbench_configuration_protocol_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) { +int print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& fp, + const ConfigProtocol& config_protocol, + const SimulationSetting& sim_settings, + 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); @@ -1140,11 +1144,11 @@ void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& f 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); + return print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(fp, + config_protocol, sim_settings, + 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: { @@ -1166,6 +1170,8 @@ void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& f "Invalid SRAM organization type!\n"); exit(1); } + + return CMD_EXEC_SUCCESS; } /******************************************************************** @@ -1974,12 +1980,17 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, VERILOG_SIM_TIMESCALE); /* Generate stimuli for programming interface */ - print_verilog_top_testbench_configuration_protocol_stimulus(fp, - config_protocol, - module_manager, top_module, - fast_configuration, bit_value_to_skip, fabric_bitstream, - prog_clock_period, - VERILOG_SIM_TIMESCALE); + int status = CMD_EXEC_SUCCESS; + status = print_verilog_top_testbench_configuration_protocol_stimulus(fp, + config_protocol, simulation_parameters, + module_manager, top_module, + fast_configuration, bit_value_to_skip, fabric_bitstream, + prog_clock_period, + VERILOG_SIM_TIMESCALE); + + if (status == CMD_EXEC_FATAL_ERROR) { + return status; + } /* Identify the stimulus for global reset/set for programming purpose: * - If only reset port is seen we turn on Reset @@ -2124,7 +2135,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, /* Close the file stream */ fp.close(); - return 0; + return status; } 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 5482b0454..da48da8b8 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -11,7 +11,11 @@ #include "vtr_assert.h" #include "vtr_time.h" +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + /* Headers from openfpgautil library */ +#include "openfpga_scale.h" #include "openfpga_port.h" #include "openfpga_digest.h" @@ -279,15 +283,48 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator( 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) { +/** + * @brief Update the clock period of shift register chain by considering the constraints from simulation settings + * - If the frequency is lower than the pre-computed bound, we should error out! Shift register chain cannot load the data completely + * - If the frequency is higher than the pre-computed bound, we use the contrained frequency + * @param sr_clock_port is the clock port which expect constraints + * @param sr_clock_period is the pre-constrained clock period. It is also the final clock period which will be return (if updated) + */ +static +int constrain_blwl_shift_register_clock_period_from_simulation_settings(const SimulationSetting& sim_settings, + const BasicPort& sr_clock_port, + const float& timescale, + float& sr_clock_period) { + for (const SimulationClockId& sim_clk : sim_settings.programming_shift_register_clocks()) { + /* Bypass all the clocks which does not match */ + if (sim_settings.clock_port(sim_clk) == sr_clock_port) { + if (sr_clock_period > 0.5 * (1 / sim_settings.clock_frequency(sim_clk)) / timescale) { + VTR_LOG_ERROR("Constrained clock frequency for BL shift registers is lower than the minimum requirement (%g %s[Hz])! Shift register chain cannot load data completely!\n", + 1. / (2. * sr_clock_period) / 1e6, + time_unit_to_string(1e6).c_str()); + return CMD_EXEC_FATAL_ERROR; + } else { + sr_clock_period = 0.5 * (1. / sim_settings.clock_frequency(sim_clk)) / timescale; + VTR_LOG("Will use constrained clock frequency (=%g %s[Hz]) for %s.\n", + sim_settings.clock_frequency(sim_clk) / 1e6, + time_unit_to_string(1e6).c_str(), + sr_clock_port.get_name().c_str()); + } + } + } + return CMD_EXEC_SUCCESS; +} + +int print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(std::fstream& fp, + const ConfigProtocol& config_protocol, + const SimulationSetting& sim_settings, + 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); @@ -313,13 +350,38 @@ void print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus( fast_configuration, bit_value_to_skip); - /* TODO: Consider auto-tuned clock period for now: + /* Compute the auto-tuned clock period first, this is the lower bound of the shift register clock periods: * - the BL/WL shift register clock only works in the second half of the programming clock period * - add 2 idle clocks to avoid racing between programming clock and shift register clocks at edge */ float bl_sr_clock_period = 0.25 * prog_clock_period / (fabric_bits_by_addr.bl_word_size() + 2) / timescale; float wl_sr_clock_period = 0.25 * prog_clock_period / (fabric_bits_by_addr.wl_word_size() + 2) / timescale; + VTR_LOG("Precomputed clock frequency (=%g %s[Hz]) for %s.\n", + 1. / (2. * bl_sr_clock_period) / 1e6, + time_unit_to_string(1e6).c_str(), + bl_sr_clock_port.get_name().c_str()); + + VTR_LOG("Precomputed clock frequency (=%g %s[Hz]) for %s.\n", + 1. / (2. * wl_sr_clock_period) / 1e6, + time_unit_to_string(1e6).c_str(), + wl_sr_clock_port.get_name().c_str()); + + + if (CMD_EXEC_FATAL_ERROR == constrain_blwl_shift_register_clock_period_from_simulation_settings(sim_settings, + bl_sr_clock_port, + timescale, + bl_sr_clock_period)) { + return CMD_EXEC_FATAL_ERROR; + } + + if (CMD_EXEC_FATAL_ERROR == constrain_blwl_shift_register_clock_period_from_simulation_settings(sim_settings, + wl_sr_clock_port, + timescale, + wl_sr_clock_period)) { + return CMD_EXEC_FATAL_ERROR; + } + 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, start_bl_sr_port, bl_sr_clock_port, bl_sr_clock_period); @@ -330,6 +392,8 @@ void print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus( print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, start_wl_sr_port, wl_sr_clock_port, wl_sr_clock_period); } } + + return CMD_EXEC_SUCCESS; } /* Verilog codes to load bitstream from a bit file for memory bank using flatten BL/WLs */ 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 d4ebf3264..e3a4edc7e 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h @@ -45,15 +45,16 @@ void print_verilog_top_testbench_global_shift_register_clock_ports_stimuli(std:: /** * @brief Generate the Verilog codes that generate stimuli waveforms for BL/WL protocols */ -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); +int print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(std::fstream& fp, + const ConfigProtocol& config_protocol, + const SimulationSetting& sim_settings, + 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