How To Customize UVM Sequencer’s Arbitration Policy

This post shows how you can implement a custom sequencer arbitration policy in UVM.

The example considers a sequence that contains a field called seq_type:

typedef enum {MASTER_SEQ, REQ_SEQ, CNFRM_SEQ, ACK_SEQ, REDO_SEQ, DATA_SEQ } ex_seq_type_t;
class ex_base_sequence extends uvm_sequence#(ex_sequence_item);
   ex_seq_type_t seq_type; // this field is used by the arbitration scheme
........
endclass

The arbitration policy uses seq_type field to decide which is the next sequence to be handled by the sequencer. All sequences running on the given sequencer should inherit the ex_base_sequence and initialize the seq_type field to the desired value:

class ex_data_seq extends ex_base_sequence;
........
    function new(string name = "my_obj");
       super.new(name);
       seq_type = DATA_SEQ;
    endfunction
........
endclass

Next step is to set sequencer’s arbitration policy to UVM_SEQ_ARB_USER either in a virtual sequence or in the agent that instantiates the sequencer:

   p_sequencer.set_arbitration(UVM_SEQ_ARB_USER);

The arbitration policy is implemented inside the user_priority_arbitration() method:

class ex_sequencer extends uvm_sequencer#(ex_sequence_item);
........
   virtual function integer user_priority_arbitration(integer avail_sequences[$]);
      uvm_sequence_request a_seq_req;
      ex_base_sequence a_seq;
      // queues that hold the indexes of different types of sequences
      int q_req[$], q_cnfrm[$], q_ack[$], q_redo[$], q_data[$]; 
      foreach(avail_sequences[i]) begin
         // cast the active sequence pointer to the ex_base_seq
         $cast(a_seq, arb_sequence_q[i].sequence_ptr); 
         // group sequences by their type
         case (a_seq.seq_type)
            MASTER_SEQ : return avail_sequences[i]; // MASTER_SEQ always wins arbitration
            REQ_SEQ    : q_sync_req.push_back(i);
            CNFRM_SEQ  : q_sync_cnfrm.push_back(i);
            ACK_SEQ    : q_ack_nack.push_back(i);
            REDO_SEQ   : q_rtx.push_back(i);
            DATA_SEQ   : q_data.push_back(i);
            default    : SQR_UNABLE_TO_ARBITRATE_ERR_1: assert (0) else `uvm_error("SQR_UNABLE_TO_ARBITRATE_ERR_1", $sformatf("Arbitration policy can not handle this type of sequence. seq_type=%d",a_seq.seq_type));
         endcase
      end
      // prioritize the sequences by their type
      if (q_sync_cnfrm.size() != 0) begin
         return avail_sequences[idxq_sync_cnfrm[0]];
      end else if (q_ack_nack.size() != 0) begin
         return avail_sequences[idxq_ack_nack[0]];
      end else if (q_sync_req.size() != 0) begin
         return avail_sequences[idxq_sync_req[0]];
      end else if (q_redo.size() != 0) begin
         return avail_sequences[q_redo[0]];
      end else if (q_data.size() != 0) begin
         //idxq_data.shuffle(); // optionally: if there are more you can randomly pick-one
         return avail_sequences[idxq_data[0]];
      end else begin
         SQR_UNABLE_TO_ARBITRATE_ERR_2: assert (0) else
         `uvm_error("SQR_UNABLE_TO_ARBITRATE_ERR", $sformatf("I am not able to arbitrate between different sequences.\nInstance %s.", get_full_name()))
      end
   endfunction
........
endclass

That’s all!

References

A detailed explanation on other sequence arbitration policies can be found here.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe to our newsletter

Do you want to be up to date with our latest articles?