diff --git a/docs/source/manual/arch_lang/simulation_setting.rst b/docs/source/manual/arch_lang/simulation_setting.rst index 32c5a3ebf..d480f4160 100644 --- a/docs/source/manual/arch_lang/simulation_setting.rst +++ b/docs/source/manual/arch_lang/simulation_setting.rst @@ -14,7 +14,10 @@ General organization is as follows ... - + + + ... + @@ -61,7 +64,10 @@ We should the full syntax in the code block below and then provide details on ea ... - + + + ... + Operating clock setting @@ -121,6 +127,22 @@ Programming clocks are defined under the XML node ```` Specify the frequency of the programming clock using an absolute value in the unit of ``[Hz]`` This frequency is used in testbenches for programming phase simulation. +.. option:: + +- ``name="`` + Specify a unique name for a clock signal. The name should match a reserved word of programming clock, i.e., ``bl_sr_clock`` and ``wl_sr_clock``. + + .. note:: The ``bl_sr_clock`` represents the clock signal driving the BL shift register chains, while the ``wl_sr_clock`` represents the clock signal driving the WL shift register chains + +- ``port="`` + Specify the clock port which the clock signal should be applied to. The clock port must be a valid clock port defined in OpenFPGA architecture description. Explicit index is required, e.g., ``clk[1:1]``. Otherwise, default index ``0`` will be considered, e.g., ``clk`` will be translated as ``clk[0:0]``. + +- ``frequency="auto|`` + Specify frequency of a clock signal in the unit of ``[Hz]``. If ``auto`` is used, the programming clock frequency will be inferred by OpenFPGA. + +- ``is_shift_register="`` + Specify if this clock signal is used to drive shift register chains in BL/WL protocols + .. note:: Programming clock frequency is typically much slower than the operating clock and strongly depends on the process technology. Suggest to characterize the speed of your configuration protocols before specifying a value! Simulator Option diff --git a/libopenfpga/libarchopenfpga/src/simulation_setting.cpp b/libopenfpga/libarchopenfpga/src/simulation_setting.cpp index 92296fe8f..ebbc50fc6 100644 --- a/libopenfpga/libarchopenfpga/src/simulation_setting.cpp +++ b/libopenfpga/libarchopenfpga/src/simulation_setting.cpp @@ -328,5 +328,9 @@ bool SimulationSetting::valid_clock_id(const SimulationClockId& clock_id) const return ( size_t(clock_id) < clock_ids_.size() ) && ( clock_id == clock_ids_[clock_id] ); } +bool SimulationSetting::constrained_clock(const SimulationClockId& clock_id) const { + VTR_ASSERT(valid_clock_id(clock_id)); + return 0. != clock_frequencies_[clock_id]; +} } /* namespace openfpga ends */ diff --git a/libopenfpga/libarchopenfpga/src/simulation_setting.h b/libopenfpga/libarchopenfpga/src/simulation_setting.h index 5625acdea..532380b26 100644 --- a/libopenfpga/libarchopenfpga/src/simulation_setting.h +++ b/libopenfpga/libarchopenfpga/src/simulation_setting.h @@ -139,6 +139,8 @@ class SimulationSetting { public: /* Public Validators */ bool valid_signal_threshold(const float& threshold) const; bool valid_clock_id(const SimulationClockId& clock_id) const; + /** @brief Validate if a given clock is constrained or not */ + bool constrained_clock(const SimulationClockId& clock_id) const; private: /* Internal data */ /* Operating clock frequency: the default clock frequency to be applied to users' implemetation on FPGA * This will be stored in the x() part of vtr::Point diff --git a/libopenfpga/libopenfpgautil/src/openfpga_scale.cpp b/libopenfpga/libopenfpgautil/src/openfpga_scale.cpp index 66364501d..222d1c41b 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_scale.cpp +++ b/libopenfpga/libopenfpgautil/src/openfpga_scale.cpp @@ -84,7 +84,7 @@ std::string unit_to_string(const float& unit) { * Convert numeric time unit to string * e.g. 1e-12 -> ps *******************************************************************/ -std::string time_unit_to_string(const float& unit) { +std::string time_unit_to_string(const float& unit, const std::string& postfix) { /* For larger than 1 unit, we do not accept */ if (1e6 < unit) { VTR_LOGF_ERROR(__FILE__, __LINE__, @@ -93,7 +93,7 @@ std::string time_unit_to_string(const float& unit) { exit(1); } - return unit_to_string(unit) + std::string("s"); + return unit_to_string(unit) + postfix; } /******************************************************************** diff --git a/libopenfpga/libopenfpgautil/src/openfpga_scale.h b/libopenfpga/libopenfpgautil/src/openfpga_scale.h index 197923548..f10abcca6 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_scale.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_scale.h @@ -18,7 +18,7 @@ bool same_float_number(const float& a, std::string unit_to_string(const float& unit); -std::string time_unit_to_string(const float& unit); +std::string time_unit_to_string(const float& unit, const std::string& postfix = "s"); float string_to_unit(const std::string& scale); 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..c933cc939 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,51 @@ 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_name(sim_clk) == sr_clock_port.get_name() && sim_settings.constrained_clock(sim_clk)) { + if (1. / (2. * sr_clock_period * timescale) > sim_settings.clock_frequency(sim_clk)) { + VTR_LOG_ERROR("Constrained clock frequency (=%g %s) for BL shift registers is lower than the minimum requirement (=%g %s)! Shift register chain cannot load data completely!\n", + sim_settings.clock_frequency(sim_clk) / 1e6, + time_unit_to_string(1e6, "Hz").c_str(), + 1. / (2. * sr_clock_period * timescale) / 1e6, + time_unit_to_string(1e6, "Hz").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) for %s.\n", + sim_settings.clock_frequency(sim_clk) / 1e6, + time_unit_to_string(1e6, "Hz").c_str(), + sr_clock_port.get_name().c_str()); + } + break; + } + } + 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 +353,37 @@ 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) for %s.\n", + 1. / (2. * bl_sr_clock_period * timescale) / 1e6, + time_unit_to_string(1e6, "Hz").c_str(), + bl_sr_clock_port.get_name().c_str()); + + VTR_LOG("Precomputed clock frequency (=%g %s) for %s.\n", + 1. / (2. * wl_sr_clock_period * timescale) / 1e6, + time_unit_to_string(1e6, "Hz").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 +394,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 diff --git a/openfpga_flow/openfpga_simulation_settings/fixed_shift_register_sim_openfpga.xml b/openfpga_flow/openfpga_simulation_settings/fixed_shift_register_sim_openfpga.xml new file mode 100644 index 000000000..0687db6cf --- /dev/null +++ b/openfpga_flow/openfpga_simulation_settings/fixed_shift_register_sim_openfpga.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh index c593994d8..5381920fe 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -83,7 +83,8 @@ echo -e "Testing separated Verilog fabric netlists and testbench locations"; run-task basic_tests/custom_fabric_netlist_location --debug --show_thread_logs echo -e "Testing user-defined simulation settings: clock frequency and number of cycles"; -run-task basic_tests/fixed_simulation_settings --debug --show_thread_logs +run-task basic_tests/fixed_simulation_settings/fixed_operating_clock_freq --debug --show_thread_logs +run-task basic_tests/fixed_simulation_settings/fixed_shift_register_clock_freq --debug --show_thread_logs echo -e "Testing Secured FPGA fabrics"; run-task basic_tests/fabric_key/generate_vanilla_key --debug --show_thread_logs diff --git a/openfpga_flow/tasks/basic_tests/fixed_simulation_settings/config/task.conf b/openfpga_flow/tasks/basic_tests/fixed_simulation_settings/fixed_operating_clock_freq/config/task.conf similarity index 100% rename from openfpga_flow/tasks/basic_tests/fixed_simulation_settings/config/task.conf rename to openfpga_flow/tasks/basic_tests/fixed_simulation_settings/fixed_operating_clock_freq/config/task.conf diff --git a/openfpga_flow/tasks/basic_tests/fixed_simulation_settings/fixed_shift_register_clock_freq/config/task.conf b/openfpga_flow/tasks/basic_tests/fixed_simulation_settings/fixed_shift_register_clock_freq/config/task.conf new file mode 100644 index 000000000..7a75ee299 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/fixed_simulation_settings/fixed_shift_register_clock_freq/config/task.conf @@ -0,0 +1,36 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = true +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +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_qlbanksr_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_shift_register_sim_openfpga.xml + +openfpga_vpr_device_layout= +openfpga_fast_configuration= + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v + +[SYNTHESIS_PARAM] +bench0_top = and2 + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test=