SystemVerilog Checker

Hi, can someone help on implementing checking the timing without using SVA?

The timing definition of two signals-(REQ, ACK) are as follows:
1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
2.REQ should stay high for 5~7 clk cycles before goes low
3.After ACK assert, REQ has to be de-asserted in 1~10 clk cycle

In reply to mlsxdx:
There are many times when SVA is a lot lot simpler.
There are other times when SVA can be complex. Below is a non-sva solution (it needs verification). I explain an alternative way to SVA in
https://verificationacademy.com/forums/systemverilog/paper-understanding-sva-engine-simple-alternate-solutions
Abstract: Understanding the engine behind SVA provides not only a better appreciation and limitations of SVA, but in some situations provide features that cannot be simply implemented with the current definition of SVA. This paper first explains, by example, how a relatively simple assertion example can be written without SVA with the use of SystemVerilog tasks; this provides the basis for understanding the concepts of multithreading and exit of threads upon a condition, such as an error in the assertion. The paper then provides examples that uses computational variables within threads; those variables can cause, in some cases, errors in SVA. The strictly emulation model with tasks solves this issue.


/* The timing definition of two signals-(REQ, ACK) are as follows:
1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
2.REQ should stay high for 5~7 clk cycles before goes low
3.After ACK assert, REQ has to be de-asserted in 1~10 clk cycle */ 

import uvm_pkg::*; `include "uvm_macros.svh" 
module top; 
    timeunit 1ns;     timeprecision 100ps;  
	bit clk, req, ack;  
    event e1, e2, e3; // for debug
	default clocking @(posedge clk); endclocking
	initial forever #10 clk=!clk;  
 
    always  @(posedge clk) treqack();  

    task automatic treqack();
        automatic bit gotack, fallreq, reqhi; 
        if($rose(req)) begin : rose
         fork 
          begin: req2end
           -> e1; 
           repeat(10) begin : rpt10 
           // 1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
             if(ack) begin : got
                gotack=1'b1; 
                disable rpt10;
             end : got
             @(posedge clk); 
           end : rpt10 
           a_gotack: assert(gotack) else `uvm_error("MYERR", "No ack after req in 10")
           if(!gotack) disable req2end; 
           -> e2;
           // 3.After ACK assert, REQ has to be de-asserted in 1~10 clk cycle
           repeat(10) begin  : rpt10b
             if(!req)  begin : negreq
               fallreq=1'b1;
               disable rpt10b; 
             end: negreq
             @(posedge clk) ;
           end : rpt10b
           a_gotfallreq: assert(fallreq) else `uvm_error("MYERR", "No fall of req in 10")
           if(!fallreq) disable req2end; // may not be needed
         end : req2end
         begin : Reqfor7 
          // 2.REQ should stay high for 5~7 clk cycles before goes low
            -> e3;
            repeat(7) begin : rpt7
              if(!req) begin : afell_req
               reqhi=1'b1;
               disable afell_req;
              end : afell_req
              @(posedge clk);
            end : rpt7
            areqhi7 : assert(reqhi) else `uvm_error("MYERR", "No reqhi for 7")
            if(!reqhi) disable Reqfor7; // may not be needed
         end : Reqfor7
         join
        end : rose
    endtask :treqack


 initial begin 
     repeat(200) begin 
       @(posedge clk);   
       if (!randomize(req, ack)  with 
           { req dist {1'b1:=1, 1'b0:=9};
             ack dist {1'b1:=1, 1'b0:=9};
           }) `uvm_error("MYERR", "This is a randomize error")
       end 
       $stop; 
    end 
endmodule   

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


In reply to ben@SystemVerilog.us:

Hi Ben, thanks for your reply. It is very helpful.
I have two doubts about the code.


           repeat(10) begin : rpt10 
           // 1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
           //[ML]---------------------------------------------------------------
           //[ML]should it be $rose(ack) instead of ack?
           //[ML]if($rose(ack)) begin : got
           //[ML]---------------------------------------------------------------
             if(ack) begin : got
                gotack=1'b1; 
                disable rpt10;
             end : got
             @(posedge clk); 
           end : rpt10 
           a_gotack: assert(gotack) else `uvm_error("MYERR", "No ack after req in 10")
           if(!gotack) disable req2end; 


         begin : Reqfor7 
          // 2.REQ should stay high for 5~7 clk cycles before goes low
            -> e3;
          //[ML]------------------------------------------------------
          //[ML] how to check lower bound >=5 clk cycles??
          //[ML]------------------------------------------------------
            repeat(7) begin : rpt7
              if(!req) begin : afell_req
               reqhi=1'b1;
               disable afell_req;
              end : afell_req
              @(posedge clk);
            end : rpt7
            areqhi7 : assert(reqhi) else `uvm_error("MYERR", "No reqhi for 7")
            if(!reqhi) disable Reqfor7; // may not be needed
         end : Reqfor7

In reply to mlsxdx:

In reply to ben@SystemVerilog.us:
Hi Ben, thanks for your reply. It is very helpful.
I have two doubts about the code.
//[ML]should it be $rose(ack) instead of ack?

[Ben] It does have to be, but it could be. Upon a rose of ack, or of ack=1 you disable the loop However, the $rose(ack) would catch the error if ack is always a 1’b1.


begin : Reqfor7 
// 2.REQ should stay high for 5~7 clk cycles before goes low
-> e3;
//[ML]------------------------------------------------------
//[ML] how to check lower bound >=5 clk cycles??
//[ML]------------------------------------------------------

Below is updated code. FOr that case, I used a counter and a check on that value.


/* The timing definition of two signals-(REQ, ACK) are as follows:
1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
2.REQ should stay high for 5~7 clk cycles before goes low
3.After ACK assert, REQ has to be de-asserted in 1~10 clk cycle */ 

import uvm_pkg::*; `include "uvm_macros.svh" 
module top; 
    timeunit 1ns;     timeprecision 100ps;  
	bit clk, req, ack;  
    event e1, e2, e3; // for debug
	default clocking @(posedge clk); endclocking
	initial forever #10 clk=!clk;  
 
    // always  @(posedge clk) treqack();  // <---- Edited to: 
    always  @(posedge clk) fork treqack(); join_none  
    task automatic treqack();
        automatic bit gotack, fallreq, reqhi;
        automatic int count;  
        if($rose(req)) begin : rose
         fork 
          begin: req2end
           -> e1; 
           repeat(10) begin : rpt10 
           // 1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
             if($rose(ack)) begin : got  
                gotack=1'b1; 
                disable rpt10;
             end : got
             @(posedge clk); 
           end : rpt10 
           a_gotack: assert(gotack) else `uvm_error("MYERR", "No ack after req in 10")
           if(!gotack) disable req2end; 
           -> e2;
           // 3.After ACK assert, REQ has to be de-asserted in 1~10 clk cycle
           repeat(10) begin  : rpt10b
             if(!req)  begin : negreq
               fallreq=1'b1;
               disable rpt10b; 
             end: negreq
             @(posedge clk) ;
           end : rpt10b
           a_gotfallreq: assert(fallreq) else `uvm_error("MYERR", "No fall of req in 10")
           if(!fallreq) disable req2end; // may not be needed
         end : req2end
         begin : Reqfor7 
          // 2.REQ should stay high for 5~7 clk cycles before goes low
            -> e3;
            repeat(7) begin : rpt7
              if(!req) begin : afell_req
               reqhi=1'b1;
               disable afell_req;
              end : afell_req
              else count=count+1'b1; 
              @(posedge clk);
            end : rpt7
            areqhi7 : assert(reqhi && count>=5) else `uvm_error("MYERR", "No reqhi for 5 to  7")
            if(!reqhi) disable Reqfor7; // may not be needed
         end : Reqfor7
         join
        end : rose
    endtask :treqack


 initial begin 
     repeat(200) begin 
       @(posedge clk);   
       if (!randomize(req, ack)  with 
           { req dist {1'b1:=1, 1'b0:=9};
             ack dist {1'b1:=1, 1'b0:=9};
           }) `uvm_error("MYERR", "This is a randomize error")
       end 
       $stop; 
    end 
endmodule     

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


In reply to ben@SystemVerilog.us:


// always  @(posedge clk) treqack();  // <---- Edited to: 
      always  @(posedge clk) fork treqack(); join_none   

Need to fire a new thread at every clocking event
Ben SystemVerilog.us

In reply to mlsxdx:

Hi, can someone help on implementing checking the timing without using SVA?
The timing definition of two signals-(REQ, ACK) are as follows:
1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
2.REQ should stay high for 5~7 clk cycles before goes low
3.After ACK assert, REQ has to be de-asserted in 1~10 clk cycle

Hi,can you please write assertion for this ?

In reply to Rohi_417:
Multiple smaller assertions is a preferred approach here.


// Requirements: 
// 1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
ap_req2ack: assert property(  
    @(posedge clk) $rose(req) |-> ##[1:10] $rose(ack) );  
// 2.REQ should stay high for 5~7 clk cycles before goes low
ap_reqHi: assert property(  
    @(posedge clk) $rose(req) |-> req[*5:7]);
//3.After ACK assert, REQ has to be de-asserted in 1~10 clk cycle 
ap_ack2req: assert property(
     @(posedge clk) $rose(req) |-> $rose(ack) [->1]  
                                   ##[1:10] $fell(req) ); 

There are some bugs in the task solution (it was not tested).
Will post an update, as the task approach showed errors when compared to the SVA solution.
And that proves that SVA is preferred, with few exceptions as explained in my paper.
Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


In reply to ben@SystemVerilog.us:
Update code for task method.


/* The timing definition of two signals-(REQ, ACK) are as follows:
1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
2.REQ should stay high for 5~7 clk cycles before goes low
3.After ACK assert, REQ has to be de-asserted in 1~10 clk cycle */ 

import uvm_pkg::*; `include "uvm_macros.svh" 
module top; 
    timeunit 1ns;     timeprecision 100ps;  
	bit clk, req, ack; 
  int delay=1;  
// Requirements: 
// 1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
ap_req2ack: assert property(  
    @(posedge clk) $rose(req) |-> ##[1:10] $rose(ack) );  
// 2.REQ should stay high for 5~7 clk cycles before goes low
ap_reqHi: assert property(  
    @(posedge clk) $rose(req) |-> req[*5:7]);
//3.After ACK assert, REQ has to be de-asserted in 1~10 clk cycle 
ap_ack2req: assert property(
     @(posedge clk) $rose(req) |-> $rose(ack) [->1]  
                                   ##[1:10] $fell(req) );   

  event e1, e2, e3, e4, e5, e6; // for debug
	default clocking @(posedge clk); endclocking
	initial forever #10 clk=!clk;  
 
    always  @(posedge clk) fork treqack(); join_none  

    task automatic treqack();
        automatic bit gotack, fallreq, reqhi;
        automatic int count;  
        if($rose(req)) begin : rose  
         fork 
          begin: req2end
           -> e1; 
           rpt10: repeat(10) begin   
           // 1.After REQ assert, ACK has to be asserted in 1~10 clk cycle
             -> e6; 
             @(posedge clk); // <-- Update 
             if($rose(ack)) begin : got  
                gotack=1'b1; 
                disable rpt10;
             end : got
             //@(posedge clk); 
           end  : rpt10 
           a_gotack: assert(gotack) else `uvm_error("MYERR", "No ack after req in 10")
           if(!gotack) disable req2end; 
           -> e2;
           // 3.After ACK assert, REQ has to be de-asserted in 1~10 clk cycle
           rpt10b: repeat(10) begin   
             @(posedge clk); // Updated 
             if(!$fell(req))  begin : negreq
               fallreq=1'b1;
               disable rpt10b; 
             end: negreq
             // @(posedge clk) ;
           end  : rpt10b
           a_gotfallreq: assert(fallreq) else `uvm_error("MYERR", "No fall of req in 10")
           if(!fallreq) disable req2end; // may not be needed
         end : req2end
         begin : Reqfor7 
          // 2.REQ should stay high for 5~7 clk cycles before goes low
            -> e3; count=1; // Update, because of the rose(req)
            rpt7: repeat(7) begin  
            $display("%t count=%d", $time, count); -> e5; 
             @(posedge clk); // Updated
              if($fell(req) || count==5) begin : afell_req // update
               reqhi=1'b1; -> e4;  $display("%t IN count=%d", $time, count); 
               disable rpt7; // Update
              end : afell_req
              else count=count+1'b1; 
              //@(posedge clk);
            end  : rpt7
            $display("%t OUT count=%d", $time, count); 
            areqhi7 : assert(reqhi && count>=5) else `uvm_error("MYERR", "No reqhi for 5 to  7")
            // if(!reqhi) disable Reqfor7; // may not be needed
         end : Reqfor7
         join
        end : rose
    endtask :treqack


 initial begin 
     repeat(200) begin 
       repeat(delay)  @(posedge clk);  
       #1; if (!randomize(req, ack, delay)  with 
           { req dist {1'b1:=1, 1'b0:=9};
             ack dist {1'b1:=1, 1'b0:=1};
             delay dist {3:=1, 4:= 1, 5:=2, 7:= 1, 12:= 1};
           }) `uvm_error("MYERR", "This is a randomize error")
       end        
       $stop; 
    end 
endmodule   

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


In reply to ben@SystemVerilog.us:

Hi Ben,

When I came back to digest the non-SVA solution, I realized that it will throw an error on the first {gotack,fallreq}. What is wrong with my understanding?

Here is the simplified example, the assertion failed on the first got_b is 0, not 1. I am surprised that got_b is not assigned successfully.

The code is put at:

Thanks,
mlsxdx

In reply to mlsxdx:
I modified your code because it was not correct in terms of threads and the forks/

See my new paper at the July Verification Horizons

Take a look at my diagram on The SystemVerilog flow of time slots and event regions

I also modified your testbench; you should avoid the time a <= value.
Use instead repeat(n) @(posedge clk); a <= value;
Follow this code, I think you’ll get it.

//The example to try to use non-SVA method to check timing relationship between a and b
//b is asserted after a asserted within 10 clk cycle

module tb;

	bit clk;
	bit enable;
	logic a,b;
	event e1,e2;
	int thread=1; 
	
	always #1 clk = !clk;
 
	always @(posedge clk) begin
	   if(enable == 1) begin 
		fork do_chk(thread); join_none 
		$display("%t thread= %d a=%b, b=%b", $realtime, thread, a, b);
		thread+=1'b1; 		
	   end 		
	end
 
	task automatic do_chk(int thread);
	   bit got_b;
	  
	   //fork: do_chk
	   -> e1;
	   if(a == 1'b1) begin  : a1
		 -> e2;
		clk_rpt: repeat(10) begin : rpt10
			@(posedge clk);
			if(b == 1) begin : b1 
		      got_b = 1;
			  disable clk_rpt;
			end : b1
		end : rpt10
		$display($time,,"thread %d got_b=%0b",thread, got_b);
        B_A_TM: assert(got_b) $display($time,,"Success!");
		    else $error($time, "thread %d Fail!", thread);
		end  : a1 // if (a == 1'b1)
		else return;  // if(!got_b) disable do_chk;	 
	endtask
 
	initial begin
	   #10 enable <= 1;
	end
 
	initial begin
		{a,b} <= 0;
		repeat(20) @(posedge clk); 
		a <= 1;
		repeat(10) @(posedge clk); 
		 b <= 1;
		repeat(20) @(posedge clk); 
	    $finish();
	end
 
	initial begin
	   $dumpfile("dump.fsdb");
	   $dumpvars(0,tb);      
	end
	
 endmodule // tb

                11 thread=           1 a=0, b=0
                  13 thread=           2 a=0, b=0
                  15 thread=           3 a=0, b=0
                  17 thread=           4 a=0, b=0
                  19 thread=           5 a=0, b=0
                  21 thread=           6 a=0, b=0
                  23 thread=           7 a=0, b=0
                  25 thread=           8 a=0, b=0
                  27 thread=           9 a=0, b=0
                  29 thread=          10 a=0, b=0
                  31 thread=          11 a=0, b=0
                  33 thread=          12 a=0, b=0
                  35 thread=          13 a=0, b=0
                  37 thread=          14 a=0, b=0
                  39 thread=          15 a=0, b=0
                  41 thread=          16 a=1, b=0
                  43 thread=          17 a=1, b=0
                  45 thread=          18 a=1, b=0
                  47 thread=          19 a=1, b=0
                  49 thread=          20 a=1, b=0
                  51 thread=          21 a=1, b=0
                  53 thread=          22 a=1, b=0
                  55 thread=          23 a=1, b=0
                  57 thread=          24 a=1, b=0
                  59 thread=          25 a=1, b=0
                  61 thread          17 got_b=0
"testbench.sv", 37: tb.do_chk.a1.B_A_TM: started at 61ns failed at 61ns
	Offending 'got_b'
Error: "testbench.sv", 37: tb.do_chk.a1.B_A_TM: at time 61 ns
                  61thread          17 Fail!
                  61 thread          18 got_b=0
"testbench.sv", 37: tb.do_chk.a1.B_A_TM: started at 61ns failed at 61ns
	Offending 'got_b'
Error: "testbench.sv", 37: tb.do_chk.a1.B_A_TM: at time 61 ns
                  61thread          18 Fail!
                  61 thread          19 got_b=0
"testbench.sv", 37: tb.do_chk.a1.B_A_TM: started at 61ns failed at 61ns
	Offending 'got_b'
Error: "testbench.sv", 37: tb.do_chk.a1.B_A_TM: at time 61 ns
                  61thread          19 Fail!
                  61 thread          20 got_b=0
"testbench.sv", 37: tb.do_chk.a1.B_A_TM: started at 61ns failed at 61ns
	Offending 'got_b'
Error: "testbench.sv", 37: tb.do_chk.a1.B_A_TM: at time 61 ns
                  61thread          20 Fail!
                  61 thread          21 got_b=0
"testbench.sv", 37: tb.do_chk.a1.B_A_TM: started at 61ns failed at 61ns
	Offending 'got_b'
Error: "testbench.sv", 37: tb.do_chk.a1.B_A_TM: at time 61 ns
                  61thread          21 Fail!
                  61 thread          22 got_b=0
"testbench.sv", 37: tb.do_chk.a1.B_A_TM: started at 61ns failed at 61ns
	Offending 'got_b'
Error: "testbench.sv", 37: tb.do_chk.a1.B_A_TM: at time 61 ns
                  61thread          22 Fail!
                  61 thread          23 got_b=0
"testbench.sv", 37: tb.do_chk.a1.B_A_TM: started at 61ns failed at 61ns
	Offending 'got_b'
Error: "testbench.sv", 37: tb.do_chk.a1.B_A_TM: at time 61 ns
                  61thread          23 Fail!
                  61 thread          24 got_b=0
"testbench.sv", 37: tb.do_chk.a1.B_A_TM: started at 61ns failed at 61ns
	Offending 'got_b'
Error: "testbench.sv", 37: tb.do_chk.a1.B_A_TM: at time 61 ns
                  61thread          24 Fail!
                  61 thread          25 got_b=0
"testbench.sv", 37: tb.do_chk.a1.B_A_TM: started at 61ns failed at 61ns
	Offending 'got_b'
Error: "testbench.sv", 37: tb.do_chk.a1.B_A_TM: at time 61 ns
                  61thread          25 Fail!
                  61 thread          26 got_b=1
                  61 Success!
                  61 thread=          26 a=1, b=1
                  63 thread          27 got_b=1
                  63 Success!
                  63 thread=          27 a=1, b=1
                  65 thread          28 got_b=1
                  65 Success!
                  65 thread=          28 a=1, b=1
                  67 thread          29 got_b=1
                  67 Success!
                  67 thread=          29 a=1, b=1
                  69 thread          30 got_b=1
                  69 Success!
                  69 thread=          30 a=1, b=1
                  71 thread          31 got_b=1