|HOME |ABOUT |ARTICLES |ACK |FEEDBACK |TOC |LINKS |BLOG |JOBS |

Tutorials

CLOCK GENERATOR

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:

EXAMPLE:
module Tb();
reg clock;
integer no_of_clocks;

parameter CLOCK_PERIOD = 5;
initial no_of_clocks = 0;
initial clock = 1'b0;

always #(CLOCK_PERIOD/2) clock = ~clock;

always@(posedge clock)
no_of_clocks = no_of_clocks +1 ;

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.

EXAMPLE:
module Tb();
reg clock;
integer no_of_clocks;

parameter CLOCK_PERIOD = 5;

initial no_of_clocks = 0;
initial clock = 1'b0;

always #(CLOCK_PERIOD/2.0) clock = ~clock;

always@(posedge clock)
no_of_clocks = no_of_clocks +1 ;

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.

EXAMPLE:
`timescale 1ns/100ps
module Tb();
reg clock;
integer no_of_clocks;

parameter CLOCK_PERIOD = 5;
initial clock = 1'b0;
always
begin
#(CLOCK_PERIOD/3.0) clock = 1'b0;
#(CLOCK_PERIOD - CLOCK_PERIOD/3.0) clock = 1'b1;
end

initial no_of_clocks = 0;

always@(posedge clock)
no_of_clocks = no_of_clocks +1 ;

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.

EXAMPLE:
parameter CLK_PERIOD = 10;
parameter DUTY_CYCLE = 60; //60% duty cycle
parameter TCLK_HI = (CLK_PERIOD*DUTY_CYCLE/100);
parameter TCLK_LO = (CLK_PERIOD-TCLK_HI);

reg clk;

initial
clk = 0;

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.

EXAMPLE:
initial clock = 1'b0;

always clock = #1 ~clock;
jitter = \$random() % range;

assign jittered_clock = #(jitter) clock;

With the above approace,over all clock period is increased. A better approach for clock divider is as follows

EXAMPLE:
parameter DELAY = TIMEPERIOD/2.0 - range/2.0;
initial clock = 1'b0;

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
initial begin
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
 << PREVIOUS PAGE TOP NEXT PAGE >>

copyright © 2007-2017 :: all rights reserved www.testbench.in::Disclaimer