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.