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 ?
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.
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.
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.
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.
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.
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 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