I would like to know if a clock generation is possible through a dedicated UVC. I have already written some code to describe the agent and the driver. However, it doesn’t work. It seems like the driver does not consume time in its run phase:
bit state = STARTING_SIGNAL_LEVEL;
vif.clock <= state;
forever begin
J_ = $urandom_range(2,1) == 2 ? JITTER/100 : -JITTER/100;
#(((NOMINAL_PERIOD/2)*(DUTY_CYCLE/100)+J_) * 1ps);
state = ~state;
vif.clock <= state;
#(((NOMINAL_PERIOD/2)*((1-DUTY_CYCLE)/100)+J_) * 1ps);
state = ~state;
vif.clock <= state;
end
I always use clock UVC and clock generation part is coded in clock interface itself. Agent sets random frequency to be used and then there are multiple sequences available to start/stop clock. driver gets the command and calls task in interface to start or stop clock accordingly. clock interface looks like this:
interface clk_if;
output clk;
bit clk_on;
int clk_high;
int clk_low;
always begin
if (clk_on) begin
clk = 1;
#clk_high;
clk = 0;
#clk_low;
end
end
task start_clock()
clk_on = 1;
endtask
endinterface
interface clk_if;
bit clock;
bit enable;
bit STARTING_SIGNAL_LEVEL;
int CLK_HIGH;
int CLK_LOW;
always begin
if(enable) begin
clock = STARTING_SIGNAL_LEVEL;
#CLK_HIGH;
clock = ~STARTING_SIGNAL_LEVEL;
#CLK_LOW;
end
end
task start_clock();
enable = 1'b1;
endtask: start_clock
task stop_clock();
enable = 1'b0;
endtask: stop_clock
endinterface: clk_if
can you load waveform to check clock is getting generated or not. Adding some prints also will help in debugging. Also I don’t see any code to program CLK_HIGH and CLK_LOW duration, this needs to be set before start_clock is called.
I don’t see any issue with the code and similar approach works fine for me. For debugging you can try replacing #CLK_HIGH and #CLK_LOW with some constant, add some print in start_clock to make sure sequence is behaving as intended. If possible try posting a sample code on what you are doing , it will be easier to help then.
In reply to rohitk:
The problem with the always blocks in your interface is that you have a race condition with the driver setting the values to be used as delays. If the always blocks inside the interface start first and enable (or clk_on) are 0, you get into a zero-delay loop and you’ll be stuck in the always block. better to code this as
always begin
wait(enable)
clock = STARTING_SIGNAL_LEVEL;
#CLK_HIGH
clock = ~STARTING_SIGNAL_LEVEL;
#CLK_LOW;
end
Yup that’s the issue, even in my UVC I have a wait statement, I somehow overlooked it when posted example code for Alex. Thanks Dave for catching this.
always begin
wait (clk_en == 1);
while (clk_en) begin
clk = 1;
#clk_high_period;
clk = 0;
#clk_low_period;
end
end
The solution for controlling one clock looks fine. Lets say my clock generator block has multiple clocks(like 10 different clocks) in different interfaces. How can I control those clocks from my test bench to start/stop or any other event has occurred at any point of time?
What’s not shown in Rohit’s example is that there is a clock agent sending sequence items to a driver controlling the clock generation. From your testbench perspective, it’s no different that controlling any other data interface.
If your 10 clock generators are independent, but all have the same functionality. you can replicate the clock agent for each clock.
All my clock generators have same functionality. They can be started/stopped at any point of time and can be frequency changed. Sometimes based on an event I have to start/stop in between the simulation. The above solution works good if it was an agent. But all my clocks are residing inside a module. It was not built in an agent as Iam restricted from doing that for clock generation. In this case, How would I approach?
You haven’t explained how one controls this clock generation module from any kind of testbench, be it a simple Verilog TB. Is it through module ports, calling tasks, or just setting variables through hierarchical reference?
In most cases, you should be able to use the bind construct to insert a module or interface into your clock generation module that reaches upwards to call tasks, or set variables in that module. For example
I will be more clear on my question. I have 10 different interfaces and each interface has a clock signal. All these clocks are driven from a module “clock_generator”. During my simulation, based on some events I have to start some of the clocks, I have to stop some of them or some of the clocks needs frequency change. We have multiple ways of doing it, but Iam looking for a best approach of implementing it, so that I can control them in a simpler way. Control here refers to stopping/starting the specific clock or set of clocks from any uvm_components and top module.