Hi, Uptill now we’ve seen different aspects of Sequences in UVM such as:
- UVM Sequences and Transactions Application
- The way “UVM Hierarchical Sequences” works?
- How Virtual Sequence Works? – Part 1
- How Virtual Sequence Works? – Part 2
One more dimension of Sequences came in my thoughts which is yet to be covered i.e. Sequence Arbitration in UVM.
Before explaining the Sequence Arbitration lets have a very quick Sequences recap – UVM Sequences are used to generate input stimulus for the Design Under Test i.e. DUT. Sequences are executed on a particular Sequencer which passes the generated Transactions to the connected Driver. To find out more details about this process click here: UVM Driver and Sequencer Communication.
Since we now know that Sequencer is the physical entity which executes the Sequences. So for a Sequencer if there is only one Sequence to get the allocation, it is very straight forward to do. But in case there are multiple Sequences competing at the same time to get the allocation of the Sequencer, there needs to be some mechanism, which is technically called “Arbitration”, is required to resolve the situation. In UVM this process is called “Sequence Arbitration”.
In UVM, if the Sequencer is extended from the uvm_sequencer it will have a built-in mechanism to arbitrate between Sequences running concurrently to get the allocation of the Sequencer. The built-in algorithm decides which Sequence gets the grant to send its Transaction items to the Driver. As per UVM 1.2, there are total 6 Arbitration schemes, out of them one can be selected using “set_arbitration()” Sequencer method from the controlling Sequence.
Following are the six Sequence Arbitration mechanism:
- UVM_SEQ_ARB_FIFO
- UVM_SEQ_ARB_WEIGHTED
- UVM_SEQ_ARB_RANDOM
- UVM_SEQ_ARB_STRICT_RANDOM
- UVM_SEQ_ARB_STRICT_FIFO
- UVM_SEQ_ARB_USER
Note: In UVM 1.2, “UVM_” is appended in the begining of the name of these six Arbitration mechanism. UVM 1.1d/UVM 1.1 have names without “UVM_“.
Please use the Arbitration mechanism names according to your UVM version to avoid the complication errors.
Now lets understand the process using the below given example –
Figure 1: Concurrent Sequences competing for the grant on Sequencer
In the shown Figure 1, master Sequence “my_seq” spawned four concurrent sub-sequences called “seq1“, “seq2“, “seq3” & “seq4“. These 4 concurrent sequences races to gain the grant so that their Transaction items could be sent to the DUT via Driver.
Lets see the UVM code of the master Sequence i.e. “master_seq” class instantiated as “my_seq” inside the Test:
///// Master Sequence To Generate Sub-Sequences ///// class master_seq extends uvm_sequence #(my_txn); `uvm_object_utils(master_seq) /// Sub-sequences class handle declaration arb_seq seq1, seq2, seq3, seq4; /// Constructor function new(string name = "master_seq"); super.new(name); endfunction: new /// Body Task task body; seq1 = arb_seq::type_id::create("seq1"); seq1.seq_no = 1; seq2 = arb_seq::type_id::create("seq2"); seq2.seq_no = 2; seq3 = arb_seq::type_id::create("seq3"); seq3.seq_no = 3; seq4 = arb_seq::type_id::create("seq4"); seq4.seq_no = 4; m_sequencer.set_arbitration(arb_type); fork begin repeat(4) begin #1; seq1.start(m_sequencer, this, 400); ///Highest priority end end begin repeat(4) begin #2; seq2.start(m_sequencer, this, 400); ///Highest priority end end begin repeat(4) begin #3; seq3.start(m_sequencer, this, 200); ///Medium priority end end begin repeat(4) begin #4; seq4.start(m_sequencer, this, 100); ///Lowest priority end end join endtask: body endclass: master_seq
The above code i.e. “master_seq” class is the master Sequence which instantiates the 4 sub-Sequences i.e. seq1, seq2, seq3 & seq4. Inside the body() task, first these sub-Sequences are created along with allocation of Sequence no. to each one of those. Next, the Arbitration mechanism is selected using set_arbitration() method. Finally, using the fork..join construct all the four sub-Sequences are spawned on the same Sequencer. Few things to observe – There is an offset provided for each sub-Sequence generation inside the repeat loop. Priorities are also defined for each sub-Sequences. Priorities are needed in some of the Arbitration mechanism as we’ll see in the section below. Since as per the topic of discussion of Sequence Arbitration, it does not really matter, much, what each of the sub-Sequence functionally performs, hence sub-Sequence code is not shown here.
Ok, now lets analyze the behavior of the six UVM Sequence Arbitration mechanism using the above given example & UVM master Sequence code.
1) UVM_SEQ_ARB_FIFO
This is the default Arbitration mechanism in UVM. It is order dependent & no priority advantage given to the sub-Sequences. It means, Sequencer send the Transaction items of the Sequences in the order these are received. Based on the above code, order by which Sequencer would send the Transactions to Driver would be: seq1, seq2, seq3 & seq4. Resultant log file would be as follows:
UVM_INFO @ 0: reporter [RNTST] Running test my_test... UVM_INFO @ 0: uvm_test_top [Sequencer Arbitration selected:] UVM_SEQ_ARB_FIFO UVM_INFO @ 1: [RECVD_SEQ] Access totals: seq1:1 seq2:0 seq3:0 seq4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: seq1:1 seq2:1 seq3:0 seq4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: seq1:2 seq2:1 seq3:0 seq4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: seq1:2 seq2:1 seq3:1 seq4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: seq1:3 seq2:1 seq3:1 seq4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:3 seq2:1 seq3:1 seq4:1 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:3 seq2:2 seq3:1 seq4:1 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:4 seq2:2 seq3:1 seq4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: seq1:4 seq2:2 seq3:2 seq4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: seq1:4 seq2:3 seq3:2 seq4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: seq1:4 seq2:3 seq3:2 seq4:2 UVM_INFO @ 8: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:2 seq4:2 UVM_INFO @ 9: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:3 seq4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:3 seq4:3 UVM_INFO @ 12: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:3 UVM_INFO @ 16: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:4
2) UVM_SEQ_ARB_WEIGHTED
Using this algorithm, grant is allocated based on the random basis but the Sequences with higher weight is given priority. In the given example/code above, seq1 and seq2 have equal weightage so first seq1 and seq2 are consumed, once available, on random basis then seq3 and at last seq4. The resultant log file shows this:
UVM_INFO @ 0: reporter [RNTST] Running test my_test... UVM_INFO @ 0: uvm_test_top [Sequencer Arbitration selected:] UVM_SEQ_ARB_WEIGHTED UVM_INFO @ 1: [RECVD_SEQ] Access totals: seq1:1 seq2:0 seq3:0 seq4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: seq1:2 seq2:0 seq3:0 seq4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: seq1:2 seq2:1 seq3:0 seq4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: seq1:3 seq2:1 seq3:0 seq4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: seq1:3 seq2:1 seq3:1 seq4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:4 seq2:1 seq3:1 seq4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:4 seq2:1 seq3:1 seq4:1 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:4 seq2:2 seq3:1 seq4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: seq1:4 seq2:3 seq3:1 seq4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: seq1:4 seq2:3 seq3:2 seq4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:2 seq4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:2 seq4:2 UVM_INFO @ 9: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:3 seq4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:3 UVM_INFO @ 16: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:4
3) UVM_SEQ_ARB_RANDOM
This mode of Arbitration is totally random in nature. It does not consider any weight or priority and grant the access just on the random basis to the available completing Sequences.
UVM_INFO @ 0: reporter [RNTST] Running test my_test... UVM_INFO @ 0: uvm_test_top [Sequencer Arbitration selected:] UVM_SEQ_ARB_RANDOM UVM_INFO @ 1: [RECVD_SEQ] Access totals: seq1:1 seq2:0 seq3:0 seq4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: seq1:2 seq2:0 seq3:0 seq4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: seq1:2 seq2:1 seq3:0 seq4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: seq1:3 seq2:1 seq3:0 seq4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: seq1:3 seq2:1 seq3:1 seq4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:3 seq2:1 seq3:1 seq4:1 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:3 seq2:2 seq3:1 seq4:1 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:4 seq2:2 seq3:1 seq4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: seq1:4 seq2:2 seq3:2 seq4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: seq1:4 seq2:3 seq3:2 seq4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:2 seq4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:2 seq4:2 UVM_INFO @ 9: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:3 seq4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:3 UVM_INFO @ 16: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:4
4) UVM_SEQ_ARB_STRICT_RANDOM
In this Arbitration scheme, random grant is allocated but weighted by the priority of the sequences. In the given example code, seq1 is selected randomly first before seq2, followed by seq3, then seq4.
UVM_INFO @ 0: reporter [RNTST] Running test my_test... UVM_INFO @ 0: uvm_test_top [Sequencer Arbitration selected] UVM_SEQ_ARB_STRICT_RANDOM UVM_INFO @ 1: [RECVD_SEQ] Access totals: seq1:1 seq2:0 seq3:0 seq4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: seq1:2 seq2:0 seq3:0 seq4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: seq1:2 seq2:1 seq3:0 seq4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: seq1:3 seq2:1 seq3:0 seq4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: seq1:3 seq2:1 seq3:1 seq4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:4 seq2:1 seq3:1 seq4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:4 seq2:2 seq3:1 seq4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: seq1:4 seq2:2 seq3:1 seq4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: seq1:4 seq2:3 seq3:1 seq4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: seq1:4 seq2:3 seq3:2 seq4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:2 seq4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:2 seq4:2 UVM_INFO @ 9: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:3 seq4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:3 UVM_INFO @ 16: [RECVD_SEQ] Access totals: seq1:4 seq2:4 seq3:4 seq4:4
5) UVM_SEQ_ARB_STRICT_FIFO
This mechanism allocates grant to the Sequences based on their priorities and order in the FIFO, with highest priority items being sent in the order received. As per the given example, seq_1 and seq_2 Sequences are being sent first interleaved with each other according to the order of their arrival in the Sequencer queue, followed by seq_3 Sequence, and then the sequence seq_4.
UVM_INFO @ 0: reporter [RNTST] Running test my_test... UVM_INFO @ 0: uvm_test_top [Sequencer Arbitration selected:] UVM_SEQ_ARB_STRICT_FIFO UVM_INFO @ 1: [RECVD_SEQ] Access totals: SEQ_1:1 SEQ_2:0 SEQ_3:0 SEQ_4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: SEQ_1:1 SEQ_2:1 SEQ_3:0 SEQ_4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: SEQ_1:2 SEQ_2:1 SEQ_3:0 SEQ_4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: SEQ_1:3 SEQ_2:1 SEQ_3:0 SEQ_4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: SEQ_1:3 SEQ_2:1 SEQ_3:1 SEQ_4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: SEQ_1:3 SEQ_2:2 SEQ_3:1 SEQ_4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:2 SEQ_3:1 SEQ_4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:2 SEQ_3:1 SEQ_4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:3 SEQ_3:1 SEQ_4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:3 SEQ_3:2 SEQ_4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:2 SEQ_4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:2 SEQ_4:2 UVM_INFO @ 9: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:3 SEQ_4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:4 SEQ_4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:4 SEQ_4:3 UVM_INFO @ 16: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:4 SEQ_4:4
6) UVM_SEQ_ARB_USER
This Arbitration mechanism allows user defined method or algorithm for the Arbitration process. To enable this feature, first condition is that Sequencer must be derived from uvm_squencer base class. Next, it requires to override a method called user_priority_arbitration(). This method inputs a Sequences queue as an argument. The user implemented algorithm needs to return an integer to select one of the Sequence from the Sequence queue.
In the following example of user defined user_priority_arbitration() method, Sequence priority order is reversed, lets take a look at the UVM code below:
///// Sequencer declaration ///// class my_sqnr extends uvm_sequencer #(my_txn); `uvm_component_utils(my_sqnr) /// The method to override the default method in base classes function integer user_priority_arbitration(integer avail_sequences[$]); int end_index; end_index = avail_sequences.size() - 1; return (avail_sequences[end_index]); endfunction: user_priority_arbitration endclass: my_sqnr
Using this code, the Sequence which is lined up last in the queue at a particular moment of contention or where Arbitration is required, that last most Sequence in the order got allocation. It can be observed & compared that USER mode release order of Sequences is just reversed of the FIFO mode by using the above mentioned user defined priority arbitration method. As a result, following log will appear:
UVM_INFO @ 0: reporter [RNTST] Running test my_test... UVM_INFO @ 0: uvm_test_top [Sequencer Arbitration selected:] UVM_SEQ_ARB_USER UVM_INFO @ 1: [RECVD_SEQ] Access totals: SEQ_1:1 SEQ_2:0 SEQ_3:0 SEQ_4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: SEQ_1:2 SEQ_2:0 SEQ_3:0 SEQ_4:0 UVM_INFO @ 2: [RECVD_SEQ] Access totals: SEQ_1:2 SEQ_2:1 SEQ_3:0 SEQ_4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: SEQ_1:3 SEQ_2:1 SEQ_3:0 SEQ_4:0 UVM_INFO @ 3: [RECVD_SEQ] Access totals: SEQ_1:3 SEQ_2:1 SEQ_3:1 SEQ_4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:1 SEQ_3:1 SEQ_4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:2 SEQ_3:1 SEQ_4:0 UVM_INFO @ 4: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:2 SEQ_3:1 SEQ_4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:3 SEQ_3:1 SEQ_4:1 UVM_INFO @ 6: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:3 SEQ_3:2 SEQ_4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:2 SEQ_4:1 UVM_INFO @ 8: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:2 SEQ_4:2 UVM_INFO @ 9: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:3 SEQ_4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:4 SEQ_4:2 UVM_INFO @ 12: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:4 SEQ_4:3 UVM_INFO @ 16: [RECVD_SEQ] Access totals: SEQ_1:4 SEQ_2:4 SEQ_3:4 SEQ_4:4
With this, all the UVM supported Sequence Arbitration algorithms are covered with their intended behavior with elementary/required details. Here purpose is to share the basic operation of the selected Arbitration algorithm.
I believe you found this write-up helpful to get initial information about Sequence Arbitration in UVM. You may get further more information on the topic from available online & offline resources. Keep sharing your inputs as many of you are already doing. I truly appreciate your responses. I always try my best to respond each one of them individually.
Thank you for your time. See you with next post soon..Till then byee!, Take care 🙂