Keywords: VHDL | testbench | clock generation | simulation
Abstract: This article explores various methods for generating clock signals in VHDL testbenches, focusing on efficient techniques such as concurrent signal assignments and the use of a 'finished' signal for controlled stopping. It also covers time resolution issues, multiple clock generation procedures, and best practice recommendations to provide thorough and practical guidance.
In VHDL simulation, generating a clock signal is fundamental for testing synchronous circuits. This guide will analyze best practices and alternative approaches in detail to help developers optimize testbench design.
Concurrent Signal Assignment Method
Based on the best answer, a preferred technique is using concurrent signal assignment statements. This method is concise and efficient, as shown in the code example:
signal clk : std_logic := '0'; -- make sure you initialise!
...
clk <= not clk after half_period;Here, half_period is defined as a time constant, e.g., constant half_period : time := 0.5 ns;. By using not clk after half_period, the clock signal automatically toggles with a 50% duty cycle, simplifying process control.
Using a Finished Signal to Control Clock Stopping
To enhance control, it can be combined with a finished signal. The code is extended as:
clk <= not clk after half_period when finished /= '1' else '0';The finished signal is defined as std_logic and can be driven from multiple processes in the test environment, such as stimulus and monitor processes. This ensures the clock stops only after all tests are complete, allowing clean simulation termination with no pending transactions.
Time Resolution Issues and Considerations
When calculating half_period, attention must be paid to the simulator's time resolution setting. For example, if the resolution defaults to nanoseconds, 5 ns / 2 might yield 2 ns, causing the clock period to become 4 ns. It is recommended to set the simulator to picoseconds or higher resolution to avoid this issue, or use procedural methods for flexible adjustment of high and low times.
Procedural Generation Method and Multiple Clock Support
Other answers provide procedural generation methods suitable for multiple clock scenarios. For instance, define a procedure clk_gen:
procedure clk_gen(signal clk : out std_logic; constant FREQ : real) is
constant PERIOD : time := 1 sec / FREQ;
constant HIGH_TIME : time := PERIOD / 2;
constant LOW_TIME : time := PERIOD - HIGH_TIME;
begin
assert (HIGH_TIME /= 0 fs) report "Error: High time is zero" severity FAILURE;
loop
clk <= '1';
wait for HIGH_TIME;
clk <= '0';
wait for LOW_TIME;
end loop;
end procedure;Through concurrent procedure calls, multiple clocks with different frequencies can be generated, e.g., clk_gen(clk_166, 166.667E6);. This method facilitates reuse and can be extended to advanced procedures for period adjustment to match frequency.
Alternative Form of Concurrent Signal Assignment
Another approach is direct concurrent signal assignment, such as:
clk <= '1' after 0.5 ns when clk = '0' else
'0' after 0.5 ns when clk = '1';This is essentially equivalent to a process statement but with more concise syntax. Simulators convert this into a process for simulation.
Conclusion and Best Practice Recommendations
In summary, clock generation should prioritize concurrent signal assignment combined with a finished signal for efficiency and controllability. For complex multi-clock tests, procedural methods are ideal, with careful attention to time resolution settings to avoid errors. It is advised to encapsulate common code in packages for reuse and balance the pros and cons of different methods based on specific needs.