How to maintain proper handshake in driver class while getting get_next_item every time?

Hi all,
I had an issue as below, whenever my driver is asking get_next_item(), my current forever loop in the drive task should get killed and should start with the new values that are sent from the transaction item. How to do this, I need help to resolve this issue. I am putting the current code that i have.

task run_phase(uvm_phase phase)
  forever begin
    seq_item_port.get_next_item(hss_clock_item_h);
    drive(hss_clock_item_h);
    seq_item_port.item_done();
  end
endtask : run_phase

task drive();
  forever begin
    #(clock_low) inf.clk =1;
    #(clock_high) inf.clk=0;
  end
endtask :drive

**Note: Where clock_low and clock_high are calculated depending upon the values that comes form transaction item for every get_next_item

In reply to KISHORE MALLA:

Here, when driver gets first item, it will call drive task, inside than also forever is there, which will caused the issue and i will never allow to call item_done() followed by next get_next_item. so, this is not recommended.
i think following code will serve your requirement.

task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(hss_clock_item_h);
drive(hss_clock_item_h);
seq_item_port.item_done();
end
endtask : run_phase

task drive(hss_clock_item item);
#(clock_low) inf.clk =1;
#(clock_high) inf.clk=0;
endtask :drive

If above code is not requirement, then kindly post your exact requirement

Regards,
Mitesh Patel

Hi Mitesh,

I am generating a clock which should change on the fly whenever new frequency is assigned to it, So if you remove the forever in the drive task, the task will get executed only once which in turn produces only one clock pulse but i need to generate a free running clock until next frequency is given which is why i gave the forever loop in the drive task.

In reply to KISHORE MALLA:

It is still unclear what the algorithm is to change the clock frequency.
And I’m not sure if generating the clock signal in a driver is a good solution.
Why do you not generate the different clocks in your toplevel module?

In reply to KISHORE MALLA:

If clock generation is the application, then i don’t think that, you need clock sequence for changing the frequency(or ppm, duty cycle etc). i would like to suggest the following code for the same.


// Get the configuration handle for clock driver, 
// Add variables/hook up for storing the clock frequency/time/ppm/duty_cycle etc.
task run_phase(uvm_phase phase);
forever
begin
  drive();
end
endtask : run_phase
 
task drive();
//Check the necessary configuration paramter for clock generation and drive according to it.
#(cfg.clock_low) inf.clk =1;
#(cfg.clock_high) inf.clk=0;
endtask :drive

Regards,
Mitesh Patel

In reply to mitesh.patel:

Unfortunately you do not retrieve any seq_item from the sequencer. This will not work.

In reply to chr_sue:

yeah i got it. but i am removing get_next_item from driver. and driving in run_phase forever. i dont need sequence or seq_item for the same. i will get the parameters from configuration class. i think as per my understanding, there is no need/will not affect sequencer driver communication of pulling the sequence, if driver does not have get_next_item.

Please correct me if i misunderstood

Regards,
Mitesh Patel

In reply to KISHORE MALLA:

You should use fork-join for this two forever-begin blocks.

In reply to Fireblade_uvm:

I don’t believe this will work.
But what you can do is executing a configuration sequence first, configuring the clock ferquency and maybe other details and then continue with a functional sequence providing the data to verify your design.

In reply to chr_sue:

I do not see it why it will not work. When all objections are dropped, test is going to an end. I agree that standard way is to configure clock and run it but here is different situation.Clock is dependent of current transaction. Could you elaborate a little bit more why two parallel forever begin-end blocks will not work?

In reply to Fireblade_uvm:

task run_phase(uvm_phase phase)
  forever begin
    seq_item_port.get_next_item(hss_clock_item_h);
    // insert code here to calculate clock_high/low
    // kills driving process. Does nothing if first time through the loop.
    disable fork;
    fork 
      drive(hss_clock_item_h);
    join_none
    seq_item_port.item_done();
  end
endtask : run_phase
 
task drive();
  forever begin
    #(clock_low) inf.clk =1;
    #(clock_high) inf.clk=0;
  end
endtask :drive

In reply to dave_59:

hi Dave,
this looks nice. I was thinking on:

fork 
  begin : process_1
    forever begin
     seq_item_port.get_next_item(hss_clock_item_h);
     // insert code here to calculate clock_high/low
     seq_item_port.item_done();
    end
  end : process_1
  begin : process_2
    forever begin
     #(clock_low) inf.clk =1;
     #(clock_high) inf.clk=0;
    end
  end : process_2
join_none

In reply to Fireblade_uvm:
Yes, the only difference is synchronization of the change. The original question asked for the change to happen immediately.

In reply to KISHORE MALLA:

How about having multiple pre-defined clocks and driver task will just do muxing between that clocks. I mean no need to generate clock in driver class, just do muxing.

task run_phase(uvm_phase phase)
  forever begin
    seq_item_port.get_next_item(hss_clock_item_h);
    drive(hss_clock_item_h);
    seq_item_port.item_done();
  end
endtask : run_phase
 
task drive();
  begin
	case (hss_clock_item_h.clk_freq)
	 100: inf.clk = inf.clk_100m;
	 200: inf.clk = inf.clk_100m;
	 endcase
  end
endtask :drive