Communication between two sequences

Hi,

I was studying some code and led to some questions. Can two sequences communicate with each other using a sequencer? i.e., sequence A will add items using start_item while sequencer B read them using sequencer.get function?.

Hi Rajmuk01,

Actually I didn’t get your complete question, but as per my understanding from your question, a sequence can call another sequence. Let me try to explain through following example.

class sub_seqs extends uvm_sequence #(xtn);

        // Factory registration $ constructor 

        virtual task body();
            req = xtn_item::type_id::create("req");
            start_item(req);
            assert(req.randomize());
            finish_item(req);
        endtask : body
     endclass : sub_seqs


     class main_seqs extends uvm_sequence#(xtn);

        // Factory registration $ constructor 

        sub_seqs seqs;   // created handle for sub_seqs
        virtual task body;
            repeat(10)
                 begin
                    seqs = sub_seqs::type_id::create("seqs");
                    seqs.start(m_sequencer);  // In-built handle
                 end
        endtask : body
    endclass : main_seqs

So, in the above code, when you call the main_seqs from driver through get_next_item via sequencer, main_seqs’s body task calls sub_seqs for 10 times and hence randomizes it for 10 times.

I hope, this clears your doubt.

Thanks & Regards,
Sachin

No. I did not mean that. Its more like one sequence sending to data to another via a sequencer. I have the put code to explain it better. I always thought get_next_item/try_next_item can be accessed only by drivers. But then UVM class library says that seq_item_export variable present in uvm_sequencer provides access to these methods. And it seems driver can access these methods only because seq_item_export is connected to seq_item_port and as such these methods are actually part of sequencer, hence this example holds good. Wanted to confirm if this is the case

   class external_sequence extends uvm_sequence #(trans_item);
         virtual task body();
            req = trans_item::type_id::create("req");
            start_item(req);
            assert(req.randomize());
            finish_item(req);
         endtask : body
     endclass

     class transaction_sequence extends uvm_sequence #(uvm_sequence_item);
        uvm_sequencer #(trans_item) sequencer;
        
        virtual function 
        void initialize(uvm_sequencer #(trans_item) sqr);
           sequencer = sqr;
        endfunction : initialize 
        
        virtual task
        body();  
           trans_item item
           sequencer.try_next_item(item);
           // Rest of the code
        endtask
     endclass

     class my_agent extends uvm_agent;
        `uvm_component_utils(my_agent)

        // Variable: sequencer
        uvm_sequencer #(trans_item) sequencer;
        transaction_sequence trans_seq; 

        virtual function
        void build_phase(uvm_phase phase);
           super.build_phase(phase); 
           sequencer = uvm_sequencer #(trans_item)::type_id::create("sequencer", this);   
           trans_seq = transaction_sequence sequence::type_id::create("trans_seq", this);
        endfunction : build_phase

        virtual task
        run_phase(uvm_phase phase);
           trans_seq.initialize(sequencer);
           trans_seq.start(null);
        endtask : run_phase
     endclass 

     class my_env extends uvm_env;
        my_agent   agentA;
        external_sequence ext_seq; 
        
        void build_phase(uvm_phase phase);
           super.build_phase(phase); 
           ext_seq = external_sequence::type_id::create("ext_seq", this);
        endfunction

        virtual task
        run_phase(uvm_phase phase);
           ext_seq.start(agentA.sequencer);
        endtask : run_phase

     endclass 

Hi Rajesh,
You are correct that the sequencer provides the implementation of get_next_item/try_next_item, so technically what you propose would work. However, I’m not sure why you would want to do such a thing. The get/try_next_item methods will return a transaction from the sequencer’s internal fifo. The sequence puts the transaction in the fifo via start_item(). Having both sequences executing on env.agentA.sequencer [and by the way, you forgot to create/instantiate agentA in the env] serves no useful purpose, since trans_seq still needs to do something with the transaction. Anything it would do could just as easily be done in ext_seq. Even worse, there’s now no transaction left in the fifo for the driver to get. It would make no sense for trans_seq to call start_item() to send it to the driver, since that would just be putting the item back into the same fifo.
The only time we recommend calling the sequencer methods directly is from a translation sequence when you are implementing a layered protocol. See the Cookbook for more details.
Good luck,
-Tom