This text is mostly lifted from the Simulated Clock Generation section of my Verilog Coding Standard. Credit goes to Claire Wolf (@oe1cxw) for teaching me this finer point of Verilog simulation.
NOTE: This code cannot work in Verilator, which can only simulate synthesizable Verilog, and thus does not support delayed assignments. Simulate the clock in the C++ testbench instead, or if you must use Verilog, try the Icarus Verilog simulator.
NOTE: This clock cannot be used directly as a periodic data signal. It causes a race condition in the Verilog simulation event queue. I have not yet found a solution.
In simulation, a race condition can exist at time zero between the initial value assignment of a register and the first clock edge. For example:
reg clock = 1'b0; // Counts as a negedge at time zero! (1'bX -> 1'b0)
reg foo = 1'b0; // Also does 1'bX -> 1'b0 at time zero.
reg bar = 1'b0;
// Simulate the clock
always begin
#HALF_PERIOD clock = ~clock;
end
// Use the simulated clock
always @(negedge clock) begin
bar <= foo;
end
In the code above, it is unclear if the initial negative clock edge or the
initialization of foo
will simulate first, so bar
might get assigned
1'bX for the first simulation cycle, which is not what the code intends.
This race condition is another reason to only use @(posedge clock)
in
internal logic, but the same race condition will happen if the simulation
clock happens to be initialized to 1'b1.
Instead, the following clock simulation idiom avoids the race condition by
making use of undefined values and the identity operator ===
, which
matches X values exactly, instead of the equality ==
operator which
treats X as false: we leave the clock uninitialized to 1'bX, and compare it
by identity after one clock half-period delay, which then assigns it false
(1'b0).
`default_nettype none `timescale 1ns / 1ps module Simulation_Clock #( parameter CLOCK_PERIOD = 10 ) ( output reg clock ); localparam HALF_PERIOD = CLOCK_PERIOD / 2; always begin #HALF_PERIOD clock = (clock === 1'b0); end endmodule
Additionally, the following tidbits are handy to use with the resulting
clock. If you use WAIT_CYCLES
or UNTIL_CYCLE
exclusively to time
actions, without using #
delays, then a timescale
directive is not
necessary anywhere else, and your simulation will run at the correct
simulated rate.
`define WAIT_CYCLES(n) repeat (n) begin @(posedge clock); end
time cycle = 0;
always @(posedge clock) begin
cycle = cycle + 1;
end
`define UNTIL_CYCLE(n) wait (cycle == n);