Clock generation through UVC

Hi everybody,

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

If you have any hints, I’ll be glad to hear them.

Thanks.

In reply to louis-alexandre.latchimy:

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

In reply to rohitk:

Thanks. I’ll give it a try.

In reply to rohitk:

Unfortunately, simulation hang on:

if (clk_on) begin

Have I done something wrong ?

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

In reply to louis-alexandre.latchimy:

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.

In reply to rohitk:

I set CLK_HIGH and CLK_LOW in the start_of_simulation phase of my driver as follow:

function void start_of_simulation_phase(uvm_phase phase);
    super.start_of_simulation_phase(phase);

    vif.STARTING_SIGNAL_LEVEL = STARTING_SIGNAL_LEVEL;
    vif.CLK_HIGH	= ((NOMINAL_PERIOD/2)*(DUTY_CYCLE/100));
    vif.CLK_LOW		= ((NOMINAL_PERIOD/2)*((1-DUTY_CYCLE)/100));
    /*
    STARTING_SIGNAL_LEVEL, NOMINAL_PERIOD and DUTY_CYCLE come from
    a configuration object
    */
endfunction: start_of_simulation_phase

Nothing is generated in the waveform.

In reply to louis-alexandre.latchimy:

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.

Rohit

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

In reply to dave_59:

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

In reply to rohitk:

Thanks guys.

Hi Everyone,

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?

Thanks,
Anudeep

In reply to Anudeep J:

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.

In reply to dave_59:

Thanks Dave.

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?

In reply to Anudeep J:

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

module clockgen (output bit clk);
  real period=50/1ns;
  always #(1ns*period/2) clk=!clk;
endmodule

module clockgen_binder;
  function void set_period(real p);
     clockgen.period = p;
  endfunction
endmodule

module tb_top;
...
  bind clockgen clockgen_binder cgb();
...
endmodule

Then read my DVCon paper on how to connect UVM drivers to modules using abstract classes.

In reply to dave_59:
Thanks Dave for the reply.

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.

In reply to Niranjan Kumar Naidu:

See:

https://verificationacademy.com/forums/uvm/how-generate-clock-driver#reply-38287