Output Monitor doesnt take the changed value

Dear Forum,

The issue which I have is connected with the output monitor module, it does not recognize the signal change.

My DUT has wfull signal, which goes to high when the memory becomes full.
And the output monitor at each wclk-clock posedge takes the value of wfull signal, puts it in transaction and sends to scoreboard.
Now when the wfull signal goes to high, than output monitor does not recognize that, and it sends the previous value of wfull to scoreboard. Please see below the picture for more details

Can you please help understand what is going here and how I can make the output monitor to catch the changed value of wfull signal?

Thanks
Hayk

You are going to have to post the relevant source code if you want some assistance.

In reply to cgales:

Dear Cgales,

Please see the code below:

outputMonitor:

class outputMonitor extends uvm_monitor;
....
task run_phase (uvm_phase phase);
...
 forever
    @(posedge itf.wclk)
      begin
	$display("%t:outputMonitor - got itf.wclk posedge, checking if in write mode", $time);
	 if (itf.winc == 1'b1 && itf.wrst_n == 1'b1)
	 begin
	  $display("%t:outputMonitor - in WRITE mode calling CollectandSendWRITEdata task: winc=%b, wrst_n=%b", $time, itf.winc, itf.wrst_n);
	   CollectandSendWRITEdata;
	 end
	    else
	      $display ("%t: outputMonitor -Not in write mode: winc=%b, wrst_n=%b", $time, itf.winc, itf.wrst_n);	
	end
...
task CollectandSendWRITEdata ;
       $display("%t: --- outputMonitor-CollectandSendWRITEData: %h ", $time, itf.wdata);
       	writeTrans.wdata = itf.wdata;
	  $display("----> %t wfull value: %d", $time, itf.wfull);
	    #1 // Added this delay here hoping to fix the issue
          $display("=====>> %t wfull value: %d", $time, itf.wfull);
	    writeTrans.wfull = itf.wfull;
	    writeData_port.write(writeTrans);
	   $display("%t: ===> inputMonitor-data send %h ", $time, itf.wdata);
    endtask
endclass


class scoreboard extends uvm_subscriber #(seqItem);
 `uvm_component_utils(scoreboard)

uvm_tlm_fifo #(seqItem) wroteDataFifo; // this fifo keeps the copy of write data, send by output monitor
...
task run_phase (uvm_phase phase);
int writeNumber, readNumber;
    forever
    fork
       begin
	wroteData_f.get(writeTrans);
	`uvm_info("SB",$sformatf(" Got Write Transaction : data=%h",writeTrans.wdata), UVM_LOW);
           wroteDataFifo.put(writeTrans); 
	     checkFull (  );
        end
   ...
   join_any
endtask

function void checkFull ();
  	if ( wroteDataFifo.is_full() )
	begin
	  $display ("%t: !!!!!!! FIFO should be F U L L", $time);
	  $display ("%t: Checking wfull value: %b", $time, this.writeTrans.wfull);
	  if	(this.writeTrans.wfull == 1'b1)
	    begin
	     `uvm_info("SB",$sformatf(" P A S S -- FIFO wfull test Pass: %b",this.writeTrans.wfull), UVM_LOW); 
	    end
	     else
		`uvm_fatal("SB",$sformatf(" FIFO wfull shows wrong value: %b",this.writeTrans.wfull) );				
	end	
	else
	  $display ("%t: scoreboard - NOT Full: number of used = %d",$time, this.wroteDataFifo.used());
endfunction
...
endclass

My guess is that wfull is being driven by your DUT and is sensitive to the clock edge. When wclk goes high, the DUT will sense it’s inputs and drive wfull as a response. Even though it seems like wfull goes high at the same time that the clock does, in reality you will find that it goes high AFTER the clock edge, resulting in the wfull being sensed as 0 on the actual clock edge.

Practically(in hardware), sampling behaviour should be like that, i.e @78 DUT drives wfull equal to 1. So when it is being sampled @78, sampling value should be equal to previous value, which is 0 in your case.

Still, if there is need to get updated value of signal on the same edge on which that signal is driven, clocking block can be used, SV 1800-1200 LRM, page#311 example.

module top;
  int a_in;
  bit clk;

  //clock
  initial
  begin
    forever begin
      #1 clk = !clk;
    end
  end

  // clocking block
  clocking cb @(posedge clk);
  endclocking // cb

  // sampling: It is not guaranteed a_in is update or old.
  always@(posedge clk)
  begin
    $display("time = %t, debug: sampling on posedge clk a_in = %d", $realtime, a_in);
  end

  // sampling: It is guaranteed a_in is updated value.
  always@(cb)
  begin
    $display("time = %t, debug: sampling on cb a_in = %d", $realtime, a_in);
  end

  // driving
  always@(posedge clk)
  begin
    a_in = a_in +1;
    $display("time = %t, debug: driving a_in = %d", $realtime, a_in);
  end

  // Stop simulation
  initial
  begin
    #50 $finish;
  end
endmodule // top

In reply to prashant.kaushik:

It seems your device is synchronized on the rising edge of clk. If you are sampling the monitor on the falling edge it should work and you are avoiding the clocking block. This is how I solve issues like this.

In reply to chr_sue:

Thank you all for the comments.

I resolved the issue as @chr_sue has suggested.

@prashant.kaushik I need to analyse how to add clocking block in my test environment, as it has several clocks there, I assume it needs lots of modifications in the code((

I also was thinking to add verilog #0 delay before taking the wfull value, but it also doesn’t work((

Thank you all for the answers.

In reply to haykp:

#0 moves you from one region to the next one in a certain timeslot. For details see the SystemVerilog scheduler. This is the reason it did not work.

Glad that it works now.

In reply to chr_sue:

chr_sue, just curious, how would you handle a DDR interface if both clock edges are used to sample data? Create a 2x clock? or use a clocking block?

In reply to dhserfer:

A clocking bock is a means to avoid races between TB and DUT automatically. In all my UVM projects I did so far, and this is more than 15, I never used a clocking block. In the case of DDR it might be useful to have a 2x clk. You have to investigate the problem and than make a decision. There is no general way.