Lock a sequencer from virtual sequence

Below is my sample virtual sequence from which I am driving two other sequences. Trying to lock a sequence on a particular seqr from p_seqr. But it is not working as expected. Can you please guide me in this?

//sample code
typedef base_seq uvm_sequence#(my_sequence_item);
class my_seq extends base_seq;

  `uvm_declare_p_sequencer(virtual_seqr); //virtual sequencer, which has so many sequencer pointers and config objects
  function new ();
  ...

  virtual task body();
    SEQA seqa;
    SEQB seqb;
    fork
      begin
        @(p_sequencer.vif.interrupt); //not exactly this way, but waiting for some uvm_event
        sqa = SEQA::type_id_create ("seqa");
        assert (sqa.randomize());
        p_sequencer.seqr.lock( sqa ); // Lock is not working - start menthod not getting called
        sqa.start(p_sequencer.seqr);
        p_sequencer.seqr.unlock( sqa );
      end
      begin
        sqb = SEQB::type_id_create ("seqb");
        assert (sqb.randomize());
        sqb.start(p_sequencer.seqr);
      end
    join
  endtask

endclass

In reply to adityaprasad123:

Can you explain more about what you mean by ‘not working as expected’? What does happen vs what do you expect to happen?

From the documentation: A lock request will be arbitrated the same as any other request. A lock is granted after all earlier requests are completed and no other locks or grabs are blocking this sequence.

Are you seeing different behavior?

In reply to cgales:

Hi cgales,

Thanks for the reply. sqa.start(p_sequencer.seqr); is not executing at all. only seqb is completed and the test is getting killed. If I remove the lock on the sequencer, both sequences are interleaving.

In all the examples, I referred to, the lock is always called from the body of a sequence which is generating seq_items. Is it not possible to call lock from a virtual sequence as in my case?

In reply to adityaprasad123:

Looking at the UVM Cookbook regarding locks, you want to pass the sequence doing the locking instead of the sub-sequence.

Try this:


  virtual task body();
    SEQA seqa;
    SEQB seqb;
    fork
      begin
        @(p_sequencer.vif.interrupt); //not exactly this way, but waiting for some uvm_event
        sqa = SEQA::type_id_create ("seqa");
        assert (sqa.randomize());
        p_sequencer.seqr.lock( this ); // Lock the sub-sequencer by 'this' sequence
        sqa.start(p_sequencer.seqr);
        p_sequencer.seqr.unlock( this ); // Unlock the sub-sequencer
      end
      begin
        sqb = SEQB::type_id_create ("seqb");
        assert (sqb.randomize());
        sqb.start(p_sequencer.seqr);
      end
    join
  endtask

In reply to cgales:
I tried with
p_sequencer.seqr.lock( this ); // Lock the sub-sequencer by ‘this’ sequence

but still, it is not working. Could you please help?

In reply to adityaprasad123:

Without a running representative testcase, it is difficult to isolate the issue. The lock() call waits until the sequence is arbitrated, so it’s possible that other sequences are being run which competes with this sequence.

Have you tried using grab()/ungrab()? This will preempt the arbitration and take immediate control of the sequencer.

In reply to adityaprasad123:

In reply to cgales:
I tried with
p_sequencer.seqr.lock( this ); // Lock the sub-sequencer by ‘this’ sequence
but still, it is not working. Could you please help?

Dou know this example

Please try it and compare with your approach.

In reply to chr_sue:

In reply to adityaprasad123:
Dou know this example
UVM: Virtual sequence calling lock(1) - EDA Playground
Please try it and compare with your approach.

Thanks for pointing the example. Now it is working, after i changed the sequence start method call as it was in the example.

sqa.start(p_sequencer.seqr, this); //working
sqa.start(p_sequencer.seqr); // Not working

In reply to adityaprasad123:

The second argument of the call to start is important because it identifies the calling sequence, whichis the virtual sequence that currently has the lock, as the parent of child sequence; Without thisargument, the child sequence would be blocked from running until the virtual sequence had called unlock, leading to immediate deadlock.

It is challenging to pinpoint the problem without a functioning representative testcase. It’s conceivable that other sequences are being performed that compete with this sequence since the lock() function waits until the sequence is arbitrated.

In reply to Agnes0:
This is not correct. The lock sequence does not belong to the arbitration process. It has precedence over all other sequences.
See here a running example

In reply to chr_sue:

According to the documentation for uvm_sequence_base for lock()

A lock request will be arbitrated the same as any other request. A lock is granted after all earlier requests are completed and no other locks or grabs are blocking this sequence.

As opposed to grab()

A grab request is put in front of the arbitration queue. It will be arbitrated before any other requests. A grab is granted when no other grabs or locks are blocking this sequence.

In reply to chrisspear:

My understanding of the lock is that the call to lock suspends any sequences already running on the sequencer and gives the virtual sequence that called lock exclusive control over the sequencer until unlock has ben called.

In reply to chr_sue:

Have a look at uvm_sequencer_base.svh source code. Both lock() and unlock() call m_lock_req(), just with a different flag. Here is the key code that adds the requested sequence to the queue.

task m_lock_req(..., bit lock);
  ...
  if (lock == 1) begin
    // Locks are arbitrated just like all other requests
    arb_sequence_q.push_back(new_req);
  end else begin
    // Grabs are not arbitrated - they go to the front
    arb_sequence_q.push_front(new_req);
  end
  ...
endtask

In reply to chrisspear:

Thanks Chris.
I visited the UVM Standard.
It says:
“A lock request is arbitrated the same as any other request. A lock is granted after all previously arbitrated requests are completed and no other locks or grabs are blocking this sequnnce.”
Nothing is suspended.

In reply to chr_sue:

We may be in total agreement. To me, suspend means that a process or thread stops running because of an outside action, like how on a CPU, a hardware interrupt suspends the current process. This is not what is happening with sequences. A sequence calls start_item() and fully expects to be blocked if the driver is still sending another item, or the sequencer is locked or grabbed.

If sequence A calls lock() after sequences B and C call start_item(), the current items for B and C won’t be blocked (or suspended). When B and C make their next calls to start_item(), those will be blocked until A unlocks.

I am assuming FIFO arbitration. I have not tried this with other arbitration algorithms.