Code for handling asynchronous reset in uvm driver

Hi All,

Wanted to understand how do we handle asynchronous reset in driver code in uvm?

In my tb I have writted code for it in the following manner:


task get_and_drive();
  @(posedge vif.clk or negedge vif.reset_n)
    begin
      if(!(vif.reset_n)bnegin
         vif.a <= 0;
         vif.b <= 0;
         vif.in <=0;
      end
      //Rest of driver code
  endtask

When I apply reset some where in the middle of the transaction the code is not entering the if condition and the signals are not becoming zero.
Before this task I have written a reset_phase task. This works when the initial reset is called.

Please help me on this topic. If any code change needs to be done to handle asynchronous reset.

Regards,
Abhinandan

Try the following ::

task run_phase( uvm_phase phase);

 forever begin

   fork
      detect_rst();
      get_and_drive();  // Has forever loop within the task
   join_any
       // will come here only when reset is asserted
       disable fork;
       wait( reset_n == 1 );  // Wait till reset is de-asserted
  end 
endtask

task detect_rst();
   @(negedge vif.reset_n);
         vif.a <= 0;
         vif.b <= 0;
         vif.in <=0;
endtask

task get_and_drive();
  //forever @(posedge vif.clk) begin  // ORG
  forever begin
      seq_item_port.get_next_item(req);
       @(posedge vif.clk);
      // Drive signals via NBA
        vif.a <= req.a;
        vif.b <= req.b;
        vif.in <=req.in;
      seq_item_port.item_done();
   end
 endtask

You are showing us a task called get_and_drive yet there is no mention of how you are getting transactions from the sequencer. Most likely your code is blocked somewhere else when the reset occurs.

If the driver is a single cycle non-pipelined, you can do something like:

forever @(posedge vif.clk or negedge vif.reset_n)
    begin
      if(!(vif.reset_n) begin
         vif.a <= 0;
         vif.b <= 0;
         vif.in <=0;
      end else if (seq_item_port.try_next_item(req)) begin
          //Rest of driver code
          seq_item_port.item_done();
      end

Driving logic that spans multiple clock cycles becomes increasingly complex. To manage those cases, you must terminate any ongoing sequences and exit and restart any loops within the driver. You’ll need to provide more details on how the driver is supposed to behave.

Hi @AGS91 ,

Thanks for the response. One doubt I have, why do we againg need forever inside the get_and_drive task, when that task itself is being called inside a forever loop?

Regards,
Abhinandan

Hi @dave_59 ,

Thanks for the reply.
So in the run_task I have the following code:

forever begin
seq_item_port.get_next_item(req);
uvm_info(get_name(),"Seq items is get",UVM_LOW); get_and_drive(); uvm_info(get_name(),“ADC Drive is done”,UVM_LOW);
seq_item_port.item_done();
end

Regards,
Abhinandan

I wasn’t aware that you call get_and_drive() within forever loop.

Hi Dave,
While reviewing the above code, for a scenario where reset_n is asserted at the same clock that driver is driving the signals ( i.e get_next_item has unblocked and driver is driving the signals on the nearest posedge of clk )

As driver would be driving the signals via Non-blocking assignment in both of the tasks
is there a possibility of race condition ?

One way to overcome this would be to call uvm_wait_for_nba_region()

  task detect_rst();
     @(negedge vif.reset_n);
     uvm_wait_for_nba_region();  
         vif.a <= 0;
         vif.b <= 0;
         vif.in <=0;
  endtask
   

Are there any other blocking statements inside the //Rest of driver code?

Hi @AGS91 @dave_59 ,
There are wait statements in the //Rest of driver code.

Regards,
Abhinandan

Hi @AGS91 ,

I am using non block assignments in the //Rest of driver code.

Try this:

task get_and_drive();
 fork
   @(negedge vif.reset_n) begin
      if(!(vif.reset_n) begin
         vif.a <= 0;
         vif.b <= 0;
         vif.in <=0;
      end 
   else
   @(posedge vif.clk iff vif.reset_n) begin
      //Rest of driver code
      end
   join any
  disable fork;
endtask

Dave, in the following code

task get_and_drive();
 fork
   @(negedge vif.reset_n) begin
      if(!(vif.reset_n) begin
         vif.a <= 0;
         vif.b <= 0;
         vif.in <=0;
      end 
   else
   @(posedge vif.clk) begin
       seq_item_port.get_next_item(req);       
        vif.a <= req.a;
        vif.b <= req.b;
        vif.in <=req.in;
       seq_item_port.item_done();
   end
   join any
  disable fork;
endtask

If negedge vif.reset_n and posedge vif.clk were true at same instant, assuming that get_next_item unblocks immediately, is the order of non-blocking assignments deterministic ?

In this case when the disable fork executes,is it possible that signals ‘a’ , ‘b’ , ‘in’ have the values from request item and not value of 0 ?

I added @(posedge vif.clk iff vif.reset_n) to make sure the clock never triggers while reset is active. If negedge reset_n occurs afterwards, the ordering of the non-blocking assignments are preserved.

The original post had get_next_item() outside the task call. If you put it inside, there is the potential to miss the reset edge.