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
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
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
`default_nettype none 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:
`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);
Back to FPGA Design Elements