Search form

Main menu

My Account Menu

Delay stimulus to be stored in scoreboard

jasonkee111
jasonkee111
Full Access
2 posts

Hi. I am learning systemverilog. I have a simple design accumulator(DUT). Stimulus is randomized every cycle in a task and accumulated result is monitored. Result is:
# * ERROR * DUT acc is 0 :: SB acc is 2
# * ERROR * DUT acc is 0 :: SB acc is 2
# * ERROR * DUT acc is 2 :: SB acc is 3
# * ERROR * DUT acc is 2 :: SB acc is 5
# * ERROR * DUT acc is 3 :: SB acc is 11

SB(scoreboard) is always 2 cycler earlier. I have try a lot of ways to delay the scoreboard but all in vain. How to delay data generated by randomize for 2 cycle?

module top();
      reg clk = 0;
      always #50 clk = ~clk;

      intf_cnt intf(clk);
      accumulator DUT
	  (.clk(clk), .reset(intf.reset), .load(intf.load), .data(intf.data), .dout(intf.acc_out));	
	  
      testcase test(intf.TEST);
      assertion_cov acov(intf);
endmodule

program testcase(intf_cnt intf);
    environment env = new(intf);
        
    initial
        begin
           env.drvr.reset();
	  fork
	      env.drvr.drive(20);
	      env.mntr.check();
	   join		
         end
endprogram

 interface intf_cnt (input clk);
    logic reset;
    logic load;
    logic [7:0] data;
    logic [15:0] acc_out;

	default clocking cb @ (posedge clk);
	input acc_out;
	output load, data;
	endclocking
	
	modport TEST (clocking cb, output reset);
 endinterface

class environment;
     driver drvr;
     scoreboard sb;
     monitor mntr;
     virtual intf_cnt intf;
           
     function new(virtual intf_cnt intf);
         this.intf = intf;
         sb = new();
         drvr = new(intf,sb);
         mntr = new(intf,sb);
     endfunction         
endclass

class driver;
	stimulus sti;
	scoreboard sb;
	
	virtual intf_cnt intf;
	
	function new(virtual intf_cnt intf,scoreboard sb);
		 this.intf = intf;
		 this.sb = sb;
	endfunction
	
	task reset();  // rst method
		 intf.cb.data <= 0;
		 @ (negedge intf.clk);
		 intf.reset = 1;
		 @ (negedge intf.clk);
		 intf.reset = 0;
		 @ (negedge intf.clk);
		 intf.reset = 1;
		 intf.cb.load <=1;
	endtask
	
	task drive(input integer iteration);
		 repeat(iteration)
		 begin
			sti = new();
			@ (posedge intf.clk);
			  
			sti.randomize(); // Generate stimulus
			intf.cb.data <= sti.value; // Drive to DUT
			sb.store = sb.store + sti.value;	// Cal exp value and store in Scoreboard
		 end		 
	endtask
endclass

Answers

jasonkee111
jasonkee111
Full Access
2 posts

Add in:

module accumulator(clk, reset, load, data, dout);
	input clk, reset, load;
	input [7:0] data;
	output logic [15:0] dout;
          
always @( posedge clk, negedge reset)
	if(!reset)
		dout <= 0;
	else if (load)
		dout <= dout + data;
	else
		dout <= dout;
endmodule

 class monitor;
          scoreboard sb;
          virtual intf_cnt intf;
          
          function new(virtual intf_cnt intf,scoreboard sb);
               this.intf = intf;
               this.sb = sb;
          endfunction
          
          task check();
          forever
	 @ (posedge intf.clk)
          if(sb.store != intf.cb.acc_out) // Get expected value from scoreboard and compare with DUT output
                  $display(" * ERROR * DUT acc is %d :: SB acc is %d ", intf.cb.acc_out,sb.store );
              else
                  $display("           DUT acc is %d :: SB acc is %d ", intf.cb.acc_out,sb.store );
          endtask
endclass

Comments on this answer

I hope you are only doing this as an example to learn SV. You are re-inventing what the UVM does for you.

One thing I notice that you are doing wrong is using @(posedge intf.clk) instead of @(intf.cb). Once you start using clocking block inputs and outputs, you should always synchronize with the clocking block event - otherwise you will get race conditions.