Debugging sequence/driver communication

I’ve run into an issue where my sequence stops sending new items to the driver. From instrumenting the code it looks like the driver has called item_done(), but nothing happens in the sequencer past the finish_item call. The simplified code in question is :

Driver run_phase :

virtual protected task run_phase(uvm_phase phase);
  forever begin
    uvm_sequence_item tr;
    child_item req_tr = child_item::type_id::create("req_tr", this);
    `uvm_info(ID, "print 1", UVM_HIGH);
    seq_item_port.get_next_item(tr);
    if ($cast(req_tr, tr)) begin
      accept_tr(req_tr);
      begin_tr(req_tr);
      req_tr.set_id_info(tr);
      // additional actions
      end_tr(req_tr);
      `uvm_info(ID, "inner print 1", UVM_HIGH);
      seq_item_port.item_done();
    end
    else
     `uvm_error(ID, "Unknow item type passed to driver");
     `uvm_info(ID, "print 2", UVM_HIGH);
  end
endtask

Sequence body :

virtual task body();  
  repeat (x) begin
	`uvm_info(ID, "sequence print 1", UVM_HIGH);
	item = child_item::type_id::create("item");
	start_item(item);
	assert(item.randomize());	
	`uvm_info(ID, "sequence print 2", UVM_HIGH);
	finish_item(item);
	`uvm_info(ID, "sequence print 3", UVM_HIGH);
  end
endtask

Several transactions go through without issue (and this is far from the first case that I’ve run through this code). The last transaction to go through hits all the prints in the driver and then loops back around to “print 1” again. Meanwhile the sequence never hits “sequence print 3” on the last transaction send to the driver. There are more iterations expected past that transaction.

Edit : To clarify, I am wondering what could prevent the sequence from continuing despite the driver having called item_done and what strategies might be used to solve the issue? Are there any UVM base class debug messages that can be enabled that might help here?

In reply to sperber:

Hi ,

I think to get more clarity on this can you add objections and see, we can use display objections to see what is happening. objections are required for the driver atleast.

In reply to harishb_vlsi:

Several comments which may or may not help:

  • Why do you use uvm_sequence_item for your driver? The driver should be typed to the expected transaction so you don’t have to go use $cast. This typing also ensures that only the appropriate sequencer is connected to the driver.
  • I would move the item_done() call to outside of the if statement. This will prevent the driver from hanging if the #cast fails.
  • Don’t wrap your randomize() call in an assert statement. Instead, explicitly check if the return value is 0 or 1. This is because assert statements can be removed by the simulator in some cases.
  • Try using try_next_item() instead of get_next_item(). This is the non-blocking method that you can use to figure out when there is no item available from the sequencer.

Don’t use objections. They should only be used in your test and not in your sequences.

In reply to cgales:

Thankyou verymuch for your inputs.

Thanks&regards,
harish

In reply to harishb_vlsi:

Hi, cgales:
Why it is not recommended that us objections in sequences?

Thanks!

In reply to seabeam:

Objections are used to ensure that every component is ready to proceed to the next phase. It is recommended that you raise an objection at the beginning of your test, and drop the objection when your test sequence is complete. When your test sequence is complete, all of your sub-sequences should also be complete. Since the test objection envelops your test sequence/sub-sequences, there is no reason to raise an objection in any sequence.

Additionally, there are some performance penalties when raising/dropping objections which could be multiplied if you run lots of sequences.

Hi all,
I have similar problem and I have implemented source code with all above pointed suggestion in the thread. still have difficulty in sending slave reactive response to driver.

From my debug analysis, code from driver component in step:2 was executing , but it was getting different transaction object with 2’nd get_next_item call than the response transaction which is prepared by wb_transaction_resp_basic_seq and then control executing 2’nd item_done call successfully. from the wb_transaction_resp_basic_seq side, I would not see any display messages after executing start_item(rsp);.It means control is not entering back to wb_transaction_resp_basic_seq. If it enters, I would have seen printing of those messages in the simulation log file.

Here is my code snippet, would you have any other suggestions why it is not getting displayed messages from WB_SLAVE_RSP_TR1,WB_SLAVE_RSP,WB_SLAVE_RSP_TR2 and why test is hanging?

class wb_transaction_resp_basic_seq extends uvm_sequence #(wb_transaction);
virtual task body();
forever begin
        req = wb_transaction::type_id::create("req");
        rsp = wb_transaction::type_id::create("rsp");
        start_item(req)
        finish_item(req);
        `uvm_info("WB_SLAVE_REQ_TR", {"Request: ", req.sprint()}, UVM_HIGH);
        if(req.m_kind == wb_transaction::WRITE)
             ram[req.m_addr] = req.m_data;
        `uvm_info("WB_SLAVE_REQ_TR", {"starting response : "}, UVM_HIGH);
   //response traction preparation based on req transaction
        start_item(rsp);
        **rsp.copy(req);
        `uvm_info("WB_SLAVE_RSP_TR1", {"Response: ", rsp.sprint()}, UVM_HIGH);
        if(!rsp.randomize() with {if(rsp.m_kind == wb_transaction::READ) (rsp.m_data == 32'hABCD_EFAB);})  //just hard coded to see transaction flow
            `uvm_fatal("WB_SLAVE_RSP", "after randomization");
        finish_item(rsp);
        `uvm_info("WB_SLAVE_RSP_TR2", {"Response: ", rsp.sprint()}, UVM_HIGH);**
    end
endtask
endclass

class wb_slave_driver extends uvm_driver **#(wb_transaction,wb_transaction);**
   task wb_slave_driver::main_phase(uvm_phase phase);
       wb_transaction wbreq,wbresp;
       forever begin
           //1 step: preparing req seq to send back to slave response sequence      
           this.seq_item_port.get_next_item(wbreq);
           //some protocol data
            wbreq.m_addr = this.sigs.adr;
            if (this.sigs.we) begin
                wbreq.m_kind = wb_transaction::WRITE ;
                wbreq.m_data = this.sigs.wdat;
            end else begin
                 wbreq.m_kind = wb_transaction::READ ;
            end
            this.sigs.ack <= 1'b0;
            this.seq_item_port.item_done();
             
           //2 step: getting slave response from wb_transaction_resp_basic_seq sequence 
            this.seq_item_port.**get_next_item(wbresp);**
            if (wbresp.m_kind == wb_transaction::READ ) begin
                 this.sigs.rdat <= wbresp.s_rd_data;
             end

            @ (this.sigs.sck) this.sigs.ack <= 1'b1;
            @ (this.sigs.sck) this.sigs.ack <= 1'b0;
            this.seq_item_port.**item_done();**
        endtask
endclass

class wb_slave_sequencer extends uvm_sequencer # **(wb_transaction,wb_transaction)**;
    `uvm_component_utils(wb_slave_sequencer)
    function new (string name, uvm_component parent);
        super.new(name,parent);
    endfunction:new 
endclass:wb_slave_sequencer

Thanks,
Siva Sankar

In reply to gariks:

Without being able to run your code, it’s difficult to determine what your exact issue is.

One thing that may be an issue is that you randomize your response without constraining your response type. This may result in the response being a READ for a WRITE request, although I’m not sure that would cause any issue.

Can you put your example on EDAPlayground so we can see exactly what is happening?

In reply to gariks:

It is unclear to me what ‘response’ means for you.
In my understanding I can observe in the driver the virtual interface and put together a rsp sending this back to the sequencer/sequence using

seq_item_done(rsp);

In the sequence I have to perform get_response to retrieve the rsp from the rsp-stack.
Depending on the data of this rsp object I can take influence on the next req.

In your code I do not see any swnding back a rsp and I do not see any get_response. You are only working straight forward.

In reply to chr_sue:

Thank You chr_sue and cgales.
I’m able trace out the problem and it is coming due to setting of default sequence in slave agent with config_db.this default sequence was corrupting transaction fields of user sequence which is triggered from test case.need to trace it out why it is happening.

Thanks,
Siva Sankar

In reply to gariks:

The solution is to never run a default sequence, as it is a deprecated methodology.

Instead, you should start the slave sequence as part of the test.