Clocks are the main synchronizing events to which all other signals are referenced. If the RTL is in verilog, the Clock generator is written in Verilog even if the TestBench is written in other languages like Vera, Specman or SystemC. Clock can be generated many ways. Some testbenchs need more than one clock generator. So testbench need clock with different phases some other need clock generator with jitter. The very first transition of clock at time zero may be perceived as a transition because clock has an unknown value before time zero and gets assigned to a value at time zero. How this time zero clock transition is perceived is simulator dependent, and thus care must be taken.
Fallowing examples show simple clock generators with 50% duty cycles.
EXAMPLE: initial clk = 0;
always #10 clk = ~clk;
EXAMPLE: always begin clk = 0;
#10;
clk = 1;
#10;
end
EXAMPLE: always begin clk = 0;
forever #10 clk = ~clk;
end
Different testbenchs need different clock periods. It is beneficial to use parameters to represent the delays, instead of hard coding them. For example, to generate a clock starting with zero that has a 50% duty cycle, the following code can be used:
initial begin #50000;
$display("End of simulation time is %d , total number of clocks seen is %d expected is %d",$time,no_of_clocks,($time/5));
$finish;
end endmodule RESULTS:
End of simulation time is 50000 , total number of clocks seen is 12500 expected is 10000
Total number of clocks are 12500 and the expected are 1000.There are 25 % of more clocks than expected. The reason is half clock period is 2 insted of 2.5.
Make sure that CLOCK_PERIOD is evenly divided by two. If CLOCK_PERIOD is odd, the reminder is truncated the frequency of the clock generated in not what expected. If integer division is replaced by real division, the result is rounded off according to the specified resolution.
initial begin #50000;
$display("End of simulation time is %d , total number of clocks seen is %d expected is %d",$time,no_of_clocks,($time/5));
$finish;
end endmodule
RESULTS:
End of simulation time is 50000 , total number of clocks seen is 8333 expected is 10000
Look at the result, total number of clock seen are 8333, where the rest of the clocks have gone? There is some improvement than earlier example. But the results are not proper. Well that is because of `timeprecision. By default time precision is 1ns/1ns. Half of the clock period is 2.5 . It is rounded of to 3 . So total time period is 6 and resulted 8333 clocks( 50000/6) instead of (50000/5). 2.5 can be rounded to 3 or 2 . LRM is specific about this. So try out this example on your tool. You may see 12500.
Timescale And Precision Enlightment:
Delay unit is specified using 'timescale, which is declared as `timescale time_unit base / precision base
--time_unit is the amount of time a delay of 1 represents. The time unit must be 1 10 or 100
--base is the time base for each unit, ranging from seconds to femtoseconds, and must be: s ms us ns ps or fs
--precision and base represent how many decimal points of precision to use relative to the time units.
Time precision plays major role in clock generators. For example, to generate a clock with 30% duty cycle and time period 5 ns ,the following code has some error.
initial begin #50000;
$display(" End of simulation time is %d , total number of clocks seen is %d expected is %d",$time,no_of_clocks,($time/5));
$finish;
end endmodule RESULTS:
End of simulation time is 50000 , total number of clocks seen is 9999 expected is 10000
Now CLOCK_PERIOD/3.0 is 5/3 which is 1.666. As the time unit is 1.0ns, the delay is 1.666ns. But the precision is 100ps. So 1.666ns is rounded to 1.700ns only.
and when (CLOCK_PERIOD - CLOCK_PERIOD/3.0) is done, the delay is 3.300ns instead of 3.333.The over all time period is 5.If the clock generated is implemented without taking proper care, this will be the biggest BUG in testbench.
All the above clock generators have hard coded duty cycle. The following example shows the clock generation with parameterizable duty cycle. By changing the duty_cycle parameter, different clocks can be generated. It is beneficial to use parameters to represent the delays, instead of hard coding them. In a single testbench, if more than one clock is needed with different duty cycle, passing duty cycle values to the instances of clock generators is easy than hard coding them.
NOTE: Simulation with `timescale 1ns/1ns is faster than `timescale 1ns/10ps
A simulation using a `timescale 10ns/10ns and with `timescale 1ns/1ns will take same time.
always begin #TCLK_LO;
clk = 1'b1;
#TCLK_HI;
clk = 1'b0;
end
Make sure that parameter values are properly dividable. The following example demonstrates how the parameter calculations results. A is 3 and when it is divided by 2,the result is 1.If integer division is replaced by real division, the result is rounded off according to the specified resolution. In the following example is result of real number division.
EXAMPLE: module Tb();
parameter A = 3;
parameter B = A/2;
parameter C = A/2.0;
initial begin $display(" A is %e ,B is %e ,C is %e ",A,B,C);
end
endmodule RESULTS:
A is 3.000000e+00 ,B is 1.000000e+00 ,C is 1.500000e+00
Often clockgenerators are required to generate clock with jitter.The following is simple way to generate clock with jitter.
always begin jitter = $dist_uniform(seed,0,jitter_range);
#(DELAY + jitter) clock = ~clock;
end
Clock dividers and multipliers are needed when more than one clock is needed to be generated from base clock and it should be deterministic. Clock multipliers are simple to design. A simple counter does this job. Clock division is little bit tricky. TO design a lock divider i.e a frequency multiplier, first the time period has to be captured and then it is used to generate another clock. With the following approach, the jitter in the base clock is carried to derived clock.
EXAMPLE:Clock multipler with N times multiplication initial i = 0;
always @( base_clock ) begin i = i % N;
if (i == 0) derived_clock = ~derived_clock;
i = i + 1;
end
EXAMPLE:Clock division with N times division initialbegin derived_clock = 1'b0;
period = 10; // for initial clock
forever derived_clock = #(period/(2N)) ~ derived_clock;
end
always@(posedge base_clock)
begin T2 = $realtime;
period = T2 - T1;
T1 = T2;
end