Sequencer arbitration in case of lock/grab

Hi…i am running 4 sequences in fork-join block as shown below :

task body();
sqr.set_arbitration(SEQ_ARB_STRICT_RANDOM);
wr_seq=wr_sequence::type_id::create(“wr_seq”);
rd_seq=rd_sequence::type_id::create(“rd_seq”);
wr1_seq=wr1_sequence::type_id::create(“wr1_seq”);
rd1_seq=rd1_sequence::type_id::create(“rd1_seq”);
fork
wr_seq.start(sqr,this,500);//using lock
rd_seq.start(sqr,this,300);//not using lock/grab
wr1_seq.start(sqr,this,200);//using lock
rd1_seq.start(sqr,this,100);//using grab
join
endtask

Sequencer must pick rd1_seq first as it has grab(), but sequencer picked in the following order : wr_seq,rd1_seq,wr1_seq & rd_seq.
Can anyone tell me why sequencer picked in this order ?

In reply to shekher201778:

Arbitration is with sequence_items sent to the driver, not the order of sequences.

In reply to dave_59:

Hi Dave…i studied that when any sequence call start_item, then its first sequence_item is added to sequencer fifo. So if multiple sequences call start_item, then first sequence_item from all sequence is added to fifo. when driver call get_next_item(), then sequencer choose one sequence_item from fifo using arbitration mechanism & send it to driver. But if any sequence want exclusive access, it can use grab/lock. If grab is used, then sequence_item from this sequence must be picked first even if its priority is lowest. So sequencer must pick sequence_item from rd1_seq first & until it ungrabs, it must be given exclusive access. If any sequence use lock, then it will be given access when it is granted following the normal sequencer arbitration. Correct me if i am wrong.

Thanks

In reply to shekher201778:

You should read the UVM Cookbook article on Sequence Arbitration. The default arbitration method is UVM_SEQ_ARB_FIFO, which will select the sequences in order of execution, ignoring any priority. Since you started the sequences with a fork statement, the order of execution is indeterminate.

If you want the sequence priority to be taken into account, you need to specify a different arbitration method.

In reply to cgales:

Hi cgales…i used UVM_SEQ_ARB_STRICT_RANDOM arbitration method. So it should first pick items from sequence using grab() even if its priority is lowest. I have gone through “Sequence Arbitration” article also, it says sequence using grab()overrides any sequence priorities & take immediate effect.

In reply to shekher201778:

I missed the part where you set the sequencer arbitration mode.

After running some tests, I’m not sure why it is behaving in this manner. It seems that the first lock() is overriding the grab(), but I don’t know why.

I’ve reproduced your issue with an example from Verification Academy on EDA Playground.

You can change the order of the sequence start() calls in the body of ‘arb_example_seq’ and get different results, including several scenarios where multiple sequences will lock the sequencer, resulting in a hang in the environment.

Perhaps Dave can provide some additional insight.

In reply to cgales:

I believe a scenario with more than 1 lock is not useful in general. Which one should have the priority?. The UVM does not specify this. I have modified the exmple slightly and it worked as expected. The grab sequence is executed first, because it appears in the arbitration fifo at the head. Afterwards the other sequences are executed starting with the lock sequence. See here:

I used the arbitration mode UVM_SEQ_ARB_STRICT_RANDOM.

In reply to chr_sue:

The lock() and grab() methods work independently of priorities and arbitration. Think of them as operating on a separate access queue. And it’s not the sequences that you start() that get arbitrated, it’s only the items sent to the sequencer with start_item. So it you have multiple sequences all calling lock/grab in a race, it’s indeterminate which lock/grab executes first. Each subsequent lock() goes to the back of the access queue, and grabs() go to the front of the access queue.

In reply to dave_59:

In reply to chr_sue:
The lock() and grab() methods work independently of priorities and arbitration. Think of them as operating on a separate access queue. And it’s not the sequences that you start() that get arbitrated, it’s only the items sent to the sequencer with start_item. So it you have multiple sequences all calling lock/grab in a race, it’s indeterminate which lock/grab executes first. Each subsequent lock() goes to the back of the access queue, and grabs() go to the front of the access queue.

Hi Dave. You are right. Sequence items from sequence with lock() will be chosen first irrespective of priorities & arbitration mechanism. I observed this behavior while i run one such case as shown below.
task body();
sqr.set_arbitration(SEQ_ARB_STRICT_FIFO);
wr_seq=wr_sequence::type_id::create(“wr_seq”);
rd_seq=rd_sequence::type_id::create(“rd_seq”);
wr1_seq=wr1_sequence::type_id::create(“wr1_seq”);
fork
wr_seq.start(sqr,this,500);//not using lock/grab
rd_seq.start(sqr,this,300);//not using lock/grab
wr1_seq.start(sqr,this,200);//using lock
join
endtask

Here, sequencer picked items according to your explanation, from lock() sequence first irrespective of priority & arbitration mechanism, then from wr_seq & last from rd_seq using arbitration mechanism.
Between grab() & lock() running in parallel, grab() is granted first.
But in the following case, wr_seq (lock)is granted before rd1_seq(grab).
fork
wr_seq.start(sqr,this,500);//using lock
rd_seq.start(sqr,this,300);//not using lock/grab
wr1_seq.start(sqr,this,200);//using lock
rd1_seq.start(sqr,this,100);//using grab
join