My scoreboard is still running even after my sequence has stopped, how do I stop it?



//-----------Sequence-------
class fifo_write_sequence extends uvm_sequence#(fifo_seq_item);
  `uvm_object_utils(fifo_write_sequence)
  
  //---------------------------------------
  //Constructor
  //---------------------------------------
  function new(string name="fifo_write_sequence");
    super.new(name);
  endfunction
  bit full;
  
  virtual task body();
    fifo_seq_item seq;
    fifo_seq_item rsp;
    rsp=new();
    //---------------------------------------
    //Write sequence
    //---------------------------------------
    while(rsp.full!=1)
    begin
      seq=new();
      start_item(seq);
      assert(seq.randomize()with{seq.wr==1;});
      finish_item(seq);
      get_response(rsp);
      `uvm_info(get_type_name(),$sformatf("Write Respose: Full flag=%0d",rsp.full),UVM_LOW)
      $display("-----------------------------------------------------------------------------");
    end
    //---------------------------------------
    //Read sequence
    //---------------------------------------
    while(rsp.empty!=1)
    begin
      seq=new();
      start_item(seq);
      assert(seq.randomize()with{seq.rd==1;});
      finish_item(seq);
      get_response(rsp);
      `uvm_info(get_type_name(),$sformatf("Read Respose: Empty flag=%0d",rsp.empty),UVM_LOW)
      $display("-----------------------------------------------------------------------------");
    end 
    
  endtask
endclass

//Fifo Monitor
`define MON_IF vif.MONITOR.monitor_cb

class fifo_monitor extends uvm_monitor;
  
  virtual fifo_interface vif;
  int count;
  //---------------------------------------
  //Analysis port declaration
  //---------------------------------------
  uvm_analysis_port#(fifo_seq_item)ap;
  
  `uvm_component_utils(fifo_monitor)
  
  //---------------------------------------
  //Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
    ap=new("ap", this);
  endfunction
  
  //---------------------------------------
  //Build phase
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db#(virtual fifo_interface)::get(this, "", "vif", vif)) begin
       `uvm_error("build_phase", "No virtual interface specified for this monitor instance")
       end
   endfunction
  
  
  //---------------------------------------
  //Run phase
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
    super.run_phase(phase);
    forever begin
     fifo_seq_item trans;
      trans=new();
      @(posedge vif.MONITOR.clk);
      wait(`MON_IF.wr==1 || `MON_IF.rd==1);
      begin
        if(`MON_IF.wr==1) begin
          trans.wr=`MON_IF.wr;
          trans.data_in=`MON_IF.data_in;
          trans.full=`MON_IF.full;
          @(posedge vif.MONITOR.clk);
        end
        if(`MON_IF.rd==1) begin
          count++;
          trans.rd=`MON_IF.rd;
          if(count==1) begin
            @(posedge vif.MONITOR.clk);
            @(posedge vif.MONITOR.clk);
          end
          trans.data_out=`MON_IF.data_out;
          trans.empty=`MON_IF.empty;
        end
        ap.write(trans);
      end
    end
  endtask
endclass
    
//FIFO Scoreboard

class fifo_scoreboard extends uvm_scoreboard;
  
  `uvm_component_utils(fifo_scoreboard)
  //---------------------------------------
  //Analysis import declaration
  //---------------------------------------
  uvm_analysis_imp#(fifo_seq_item, fifo_scoreboard) mon_imp;
  
  fifo_seq_item que[$];
  bit [7:0]mem[7:0];
  
  //---------------------------------------
  //Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name,parent);
    i=0;
    j=0;
    mon_imp = new("mon_imp", this);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
  endfunction
  
  //---------------------------------------
  //Write function implemetation
  //---------------------------------------
 function void write(fifo_seq_item trans);
   que.push_back(trans); 
  endfunction 
  int i,j;
  virtual task run_phase(uvm_phase phase);
    forever begin
    fifo_seq_item wr_trans;
    wait(que.size()>0);
      wr_trans=que.pop_front();
      if(wr_trans.wr==1) begin
        mem[i]=wr_trans.data_in;
        i++;
        end
      else if(wr_trans.rd==1) begin
        if(wr_trans.data_out==mem[j]) begin
        `uvm_info(get_type_name(),$sformatf("------ :: EXPECTED MATCH:: ------"),UVM_LOW)
          `uvm_info(get_type_name(),$sformatf("Data: %0h,mem[%0d]=%0h",wr_trans.data_out,j,mem[j]),UVM_LOW)
        end
      else begin
          `uvm_info(get_type_name(),$sformatf("------ :: FAILED MATCH:: ------"),UVM_LOW)
        `uvm_info(get_type_name(),$sformatf("Data: %0h,mem[%0d]=%0h",wr_trans.data_out,j,mem[j]),UVM_LOW)
    end
        j++;
        end
    end
  endtask
  
endclass
        

Here is the link for full code

Even after my fifo has become empty and sequence has stopped, the scoreboard still is running. Did I do something wrong in monitor, I don’t understand.Please help me.

In reply to mikasa:

There is nothing wrong with your scoreboard still running, as this is expected behavior. Your run_phase() will end when all of your objections are dropped and all active threads will be killed.

What problems are you encountering?

In reply to cgales:

In reply to mikasa:
There is nothing wrong with your scoreboard still running, as this is expected behavior. Your run_phase() will end when all of your objections are dropped and all active threads will be killed.
What problems are you encountering?

Depth of my fifo is 8, I’m running my tb starting from fifo being empty then I have written into it until fifo is full, then I have read from it until fifo is empty again, while reading I have compared whether the data which I’m reading is same as what I have written, I expect my scoreboard to compare the output only eight times as that is the depth of fifo, but in scoreboard it is running 18 times due to which I’m getting failure in match. And I want to correct that.

In reply to mikasa:

Your behavior is caused by the #100 in the run_phase of your test.

  task run_phase(uvm_phase phase);
    fifo_write_sequence fifo_seq;
    fifo_seq = fifo_write_sequence::type_id::create("fifo_seq",this);
    phase.raise_objection( this, "Starting spi_base_seqin main phase" );
    $display("%t Starting sequence fifo_seq run_phase",$time);
    fifo_seq.start(env.agt.seq);
    #100ns;          // Your problem is caused by this delay.  
    phase.drop_objection( this , "Finished fifo_seq in main phase" );
  endtask

If you are commenting out this additional delay it works perfectly and stops after the last transactions.

In reply to chr_sue:

In reply to mikasa:
Your behavior is caused by the #100 in the run_phase of your test.

  task run_phase(uvm_phase phase);
fifo_write_sequence fifo_seq;
fifo_seq = fifo_write_sequence::type_id::create("fifo_seq",this);
phase.raise_objection( this, "Starting spi_base_seqin main phase" );
$display("%t Starting sequence fifo_seq run_phase",$time);
fifo_seq.start(env.agt.seq);
#100ns;          // Your problem is caused by this delay.  
phase.drop_objection( this , "Finished fifo_seq in main phase" );
endtask

If you are commenting out this additional delay it works perfectly and stops after the last transactions.

Thank You, it worked.

In reply to mikasa:

This isn’t the correct fix. You should be able to run your environment for any period of time after your sequence is completed with no errors.

Your problem is that your driver doesn’t de-assert the ‘rd’ signal when the transaction is complete, so you continue reading from the fifo while time continues. The correct solution is to fix your driver so that it de-asserts ‘rd’ and ‘wr’ after each transaction.

In reply to cgales:
Ok thank you, I did de-assert ‘rd’ and ‘wr’ and it does solve my problem, but there is another problem arising that there are still some failure cases, it might be in driving/sampling data from interface from/in driver/monitor. I don’t understand when exactly to do that, like you can see in my monitor’s logic I have used a workaround by using count variable,


forever begin
     fifo_seq_item trans;
      trans=new();
      @(posedge vif.MONITOR.clk);
      wait(`MON_IF.wr==1 || `MON_IF.rd==1);
      begin
        if(`MON_IF.wr==1) begin
          trans.wr=`MON_IF.wr;
          trans.data_in=`MON_IF.data_in;
          trans.full=`MON_IF.full;
          @(posedge vif.MONITOR.clk);
        end
        if(`MON_IF.rd==1) begin
          count++;
          trans.rd=`MON_IF.rd;
          if(count==1) begin
            @(posedge vif.MONITOR.clk);
          end
           @(posedge vif.MONITOR.clk);
          trans.data_out=`MON_IF.data_out;
          trans.empty=`MON_IF.empty;
        end
        ap.write(trans);
      end

because I noticed that in monitor the data is being sampled 2 clock cycle later for first read, but from second read it is being sampled on every next cycle. I’m still getting failure on some matches while success on others. I wan’t to correct this but without using count variable.
If you can please help me with that.

In reply to AJ_287:

When using clocking blocks, you don’t want to use use the clock signal as a reference. Instead, you want to use the clocking block itself:


forever begin
     fifo_seq_item trans;
      trans=new();
      @(`MON_IF);
      wait(`MON_IF.wr==1 || `MON_IF.rd==1);
      begin
        if(`MON_IF.wr==1) begin
          trans.wr=`MON_IF.wr;
          trans.data_in=`MON_IF.data_in;
          trans.full=`MON_IF.full;
          @(`MON_IF);
        end
        if(`MON_IF.rd==1) begin
          count++;
          trans.rd=`MON_IF.rd;
          if(count==1) begin
            @(`MON_IF);
          end
           @(`MON_IF);
          trans.data_out=`MON_IF.data_out;
          trans.empty=`MON_IF.empty;
        end
        ap.write(trans);
      end

In reply to AJ_287:

In reply to cgales:
because I noticed that in monitor the data is being sampled 2 clock cycle later for first read, but from second read it is being sampled on every next cycle. I’m still getting failure on some matches while success on others. I wan’t to correct this but without using count variable.
If you can please help me with that.

Your mechanism with the queue que and the mem is not working correctly. See some details here

I recommend to use an associative array in the scoreboard instead of the queue. This allows you to store the date in a non-consecutive order when using the addr as index.

In reply to cgales:

In reply to AJ_287:
When using clocking blocks, you don’t want to use use the clock signal as a reference. Instead, you want to use the clocking block itself:

Ok, thanks for pointing out.

In reply to chr_sue:

In reply to AJ_287:
Your mechanism with the queue que and the mem is not working correctly.

Yes, that is solved now. I’ll try associative array as well and see if it can be better.

In reply to AJ_287:

I saw you are sending back the response to the sequence. In this case you do not need any scoreboard and monitor. Because you can do the compare inside the sequence. This is very specific but it works. I have implemented thid mechanism in a UVM testbench for a DDR RAM.
If you need more guidance please let me know.

In reply to chr_sue: Ok sure, thanks

In reply to chr_sue:

Do you have any example in which checking happens inside the Sequence without monitor and scoreboard. It really helps to see the DDR example.

In reply to vlearner:

Please respond on my email
christoph@christoph-suehnel.de