Writing SVA sequence involving a bus

Hello,
I need to write a “sequence” in SystemVerilog matching a behavior in which all the signals in a bus rise once, but the order in which they do is not relevant.
I arrived at this solution:

sequence all_rose;
$rose(my_bus[0])[=1] intersect $rose(my_bus[1])[=1] intersect $rose(my_bus[2])[=1];
endsequence

(hope it’s correct, I made a few trials and it seems so).
In this case, the bus is only 3-bits wide, but I am wondering how to solve the same problem for a bigger bus in an efficient way (i.e.: without writing tons of repetitive code).
I tried to search the web and the LRM for solutions but I did not find any.
Thanks in advance,

Lanfranco

In reply to lanfranco.salinari:

$rose(my_bus[0])[=1] intersect $rose(my_bus[1])[=1] intersect $rose(my_bus[2])[=1];
is same as
$rose(my_bus[0])&& $rose(my_bus[1])&& $rose(my_bus[2])[=1];
because you’re taking avout sequences of 1 cycle duration, at the sampling time.
How about something like the following:


bit [31:0] my_bus; 
sequence all_rose2; 
  $past(my_bus)==32'h0000_0000 &&  (my_bus)==32'hFFFF_FFFF; 
endsequence

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us

  • SystemVerilog Assertions Handbook 3rd Edition, 2013 ISBN 878-0-9705394-3-6
  • A Pragmatic Approach to VMM Adoption 2006 ISBN 0-9705394-9-5
  • Using PSL/SUGAR for Formal and Dynamic Verification 2nd Edition, 2004, ISBN 0-9705394-6-0
  • Real Chip Design and Verification Using Verilog and VHDL, 2002 isbn 0-9705394-2-8
  • Component Design by Example ", 2001 ISBN 0-9705394-0-1
  • VHDL Coding Styles and Methodologies, 2nd Edition, 1999 ISBN 0-7923-8474-1
  • VHDL Answers to Frequently Asked Questions, 2nd Edition ISBN 0-7923-8115

In reply to ben@SystemVerilog.us:

Hello Ben,
thanks for the answer but I think my question is a bit more complex.
The code you wrote checks that my_bus goes from 32’h0000_0000 in cycle 0 to 32’hFFFF_FFFF in cycle 1.
What I would like to check is that:

  • my_bus goes from 32’h0000_0000 in cycle 0 to 32’hFFFF_FFFF in cycle N with N unspecified but >= 1, and
  • each signal of the bus changes exactly once

The sequence I posted:

sequence all_rose;
$rose(my_bus[0])[=1] intersect $rose(my_bus[1])[=1] intersect $rose(my_bus[2])[=1];
endsequence

in my opinion performs the job for a 3-wide bus.
$rose(my_bus[0]) is a boolean expression, $rose(my_bus[0])[=1] is a sequence matching in cycle x if before cycle x my_bus[0] rises exactly once, and the whole sequence matches in cycle x if there is an interval before x in which all the signals of my_bus rise exactly once, but in any order.
The question was: how do I generalize this sequence for a wider bus?
Hope it is clearer now, if not I will post a complete example.
Thanks,

Lanfranco

OK, I believe that the following may work for you. The key is this sequence that waits till
number of bits in ny_bus==32. I put the sequence into an assertion that once successfully attempted with go==1, go is disabled until success.
$countones(my_bus)==32 [->1];



import uvm_pkg::*;
`include "uvm_macros.svh"
 
module allrose;
    bit [31:0] my_bus; 
    bit clk, go=1'b1; 
    function void setgo(bit val);
        go=val;
    endfunction 
    
    initial forever #5 clk=!clk; 
    sequence q_all_rose; 
        $countones(my_bus)==32 [->1]; 
    endsequence
    
    ap_allrose: assert property(@(posedge clk) 
            go |-> (1, setgo(1'b0)) ##0 q_all_rose) setgo(1'b1); // else setgo(1'b1); 
    
    
endmodule 

Ben Cohen http://www.systemverilog.us/

  • SystemVerilog Assertions Handbook, 3rd Edition, 2013
  • A Pragmatic Approach to VMM Adoption
  • Using PSL/SUGAR … 2nd Edition
  • Real Chip Design and Verification
  • Cmpt Design by Example
  • VHDL books

In reply to ben@SystemVerilog.us:

Yes, it is closer to my goal, but still does not fulfill the requirement that individual signals must only rise, not fall.
ap_allrose is successful even if the sequence is 00000000 → 00000001 → 00000000 → FFFFFFFF, where bit 0 toggles 3 times.
Maybe some condition on monotonicity of $countones(my_bus) could help, but it is not intuitive for me.
Best regards,

Lanfranco

In reply to lanfranco.salinari:

How about having supporting logic to detect the rose, and do the $countones on that vector?



import uvm_pkg::*;
`include "uvm_macros.svh"
 
module allrose;
    bit [31:0] my_bus, rose_bus; 
    bit clk, go=1'b1; 
    function void setgo(bit val, bit [31:0] val2);
        go=val;
        rose_bus= val2;
    endfunction 
    
    initial forever #5 clk=!clk; 
    sequence q_all_rose; 
        $countones(rose_bus)==32 [->1]; 
    endsequence
    
    always @ (posedge clk) begin 
        static int i; 
        for(i=0; i <= 31; i++)
          if($rose(my_bus[i])) rose_bus[i]<=1'b1;
    end 
    
    ap_allrose: assert property(@(posedge clk) 
            go |-> (1, setgo(1'b0, 0)) ##0 q_all_rose) setgo(1'b1, 0); 
endmodule 

Ben Cohen SystemVerilog.us

In reply to ben@SystemVerilog.us:

Does the following assertion satisfy the condition!
Checking for !($fell(my_bus[i])) on each bit until the numbers of 1’s in my_bus is 32

sequence q_all_rose;
$countones(rose_bus)==32 [->1];
endsequence

generate
for (genvar j = 0; j < 31; j = j + 1) begin
ap_allrose: assert property ( @(posedge clk)
(my_bus===0) |=> (!($fell(my_bus[i])[->1]) intersect q_all_rose);
end
endgenerate

In reply to pavan yalamanchili:

How about adding the test for the fell in the loop?


    always @ (posedge clk) begin 
        static int i; 
        for(i=0; i <= 31; i++) begin 
          if($rose(my_bus[i])) rose_bus[i]<=1'b1;
          if (flag) ap_fell: assert(!$fell(my_bus[i])); 
        end
    end 

I have issues with
(my_bus===0) |=> (!($fell(my_bus[i])[->1]) intersect q_all_rose);

  1. Too many not needed attempts when my_bus==0 for many cycles. That is why I had the “go” variable that fired once.
  2. !sequence is illegal
  3. (!$fell[i][->1] is not what you want


import uvm_pkg::*;
`include "uvm_macros.svh"
 
module allrose;
    bit [31:0] my_bus, rose_bus; 
    bit clk, go=1'b1, flag; 
    function void setgo(bit val, bit [31:0] val2, fg);
        go=val;
        flag=fg;
        rose_bus= val2;
    endfunction 
    
    initial forever #5 clk=!clk; 
    sequence q_all_rose; 
        $countones(rose_bus)==32 [->1]; 
    endsequence
    
    always @ (posedge clk) begin 
        static int i; 
        for(i=0; i <= 31; i++) begin 
          if($rose(my_bus[i])) rose_bus[i]<=1'b1;
          if (flag) ap_fell: assert(!$fell(my_bus[i])); 
        end
    end 
    
    ap_allrose: assert property(@(posedge clk) 
            go |-> (1, setgo(1'b0, 0, 1)) ##0 q_all_rose) setgo(1'b1, 0, 0); 
endmodule 

Ben Cohen SystemVerilog.us

In reply to ben@SystemVerilog.us:

The last solution proposed allows to detect falling edges of bus signals, so it is in line with my request.
Having the possibility of looping in sequence and property definitions would help, however, in such situations. After all it is only syntactic sugar, since one could write equivalent but longer code by hand.
Thanks for your help,

Lanfranco

In reply to lanfranco.salinari:

One minor change, you could call the function from the sequence matched items after the go; thus:


 ap_allrose: assert property(@(posedge clk) 
            (go, setgo(1'b0, 0, 1)) |->  q_all_rose) setgo(1'b1, 0, 0); 

On “Having the possibility of looping in sequence and property definitions”, don’t expect any changes on that issue in 1800’2018 because it was never proposed. In addition, this is not a typical application, and incorporating such a thing is fairly complex.
If you do have a proposal, I would like to see it and could propose it to the committee (of which I am a member of) for 1800’2023. The proposals for 2018 are already set, and the changes are very minor.
Ben

In reply to ben@SystemVerilog.us:

Ben,

could you please help me understand a bit more on your comments…

(my_bus===0) |=> (!($fell(my_bus[i])[->1]) intersect q_all_rose);

  1. Too many not needed attempts when my_bus==0 for many cycles. That is why I had the “go” variable that fired once. … I agree with your statement!
  2. !sequence is illegal … in general is it okay to use a “not” operator, like, not(sequence). I know “not” is a property operator and not a sequence operator
  3. (!$fell[i][->1] is not what you want … I agree… consecutive repetition might have worked

can you also comment on these (I have not written the antecedent part of implication operator)
a) (!$fell[i] throughout q_all_rose))
b) ((fell[i] == 0)[*0:] intersect q_all_rose)

Thanks
Pavan

In reply to pavan yalamanchili:

(my_bus===0) |=> (!($fell(my_bus[i])[->1]) intersect q_all_rose);

  1. !sequence is illegal … in general is it okay to use a “not” operator, like, not(sequence). I know “not” is a property operator and not a sequence operator

From my book, "Guideline : Limit the use of the not property operator in properties where the property_expr is a sequence, Boolean, or property with until, eventually . Do not use the not operator in properties where the property_expr can be vacuous. The reason for this recommendation is that negated assertions that contain the implication operators are difficult to understand and can be misleading. The following property statement specifications demonstrate the issues. The requirements state that a request should never be followed by an acknowledge in the same cycle, thus if req ==1, ack must be ==0 in the same cycle).


not (req |-> ack); // Leads to incorrect results, AVOID THIS structure
req |-> not ack; //  
// Use not for consequent that is a sequence , e.g. (a |-> not(b ##1 c))
req |-> !ack; // Use logical negation for negation of a variable
not(req ##0 ack); //  Does not provide meaningfull coverage
  1. (!$fell[i][->1] is not what you want … I agree… consecutive repetition might have worked

You can use !endpoint_of_a_sequence. You have to think about its use,

can you also comment on these (I have not written the antecedent part of implication operator)


a) (!$fell[i] throughout q_all_rose)) // Not correct code. 
// ** do you mean something like 
 always @ (posedge clk) begin 
        static int i; 
        for(i=0; i <= 31; i++) begin 
          if($rose(my_bus[i])) rose_bus[i]<=1'b1;
          if (flag) ap_fell: assert(!$fell(my_bus[i])); 
          ap_t: assert property(!$fell(my_bus[i]) throughout q_all_rose); //--
        end
    end 
The " ap_t: assert property(!$fell(my_bus[i]) throughout q_all_rose); " causes concurrent assertions in the queue.  That should work. The immediate is a better solution. 
b) (($fell(my_bus[i]) == 0)[*0:$] intersect q_all_rose)
// Same as 
 (($fell(my_bus[i]) == 0)[*0] intersect q_all_rose) or // fail?? 
 (($fell(my_bus[i]) == 0)[*1] intersect q_all_rose)
.. 
 (($fell(my_bus[i]) == 0)[*n] intersect q_all_rose)
// This may work.  You'll need to test it.   Looks complicated. 
 

In reply to ben@SystemVerilog.us:

Hi Ben,
what I had in mind when proposed “Having the possibility of looping in sequence and property definitions” was a very vague idea.
I understand that there could be a better way to write:

$rose(my_bus[0])[=1] intersect $rose(my_bus[1])[=1] intersect $rose(my_bus[2])[=1]

but I am not an expert of SV syntax, so I don’t know how this could be implemented.
The only thing that comes to my mind is having “sequence variables”, e.g.:

sequence s;

s = $rose(my_bus[0])[=1] intersect $rose(my_bus[1])[=1];
for (int i = 2; i < $size(my_bus); i++) begin
s = s intersect $rose(my_bus[i])[=1]
end

But I understand that all this should be made at compile time only, unless sequences and properties can be compiled “on the fly”, like regular expressions in, say, Python (I guess this would be slower).

In any case thanks for your availability.
Best regards,

Lanfranco

In reply to lanfranco.salinari:

sequences and properties must be elaborated first before runtime.

A correction to my code because the “i” needs to be static $rose(my_bus[i]).
Though it is defined as static, it is changing in the loop, and simulation never detected the $rose.


// BAD CODE
always @ (posedge clk) begin 
        static int i; 
        for(i=0; i <= 31; i++) begin 
          if($rose(my_bus[i])) rose_bus[i]<=1'b1;

// Corrected code that simulates correctly


import uvm_pkg::*;
`include "uvm_macros.svh"
 
module allrose;
	bit [31:0] my_bus, rose_bus; 
	bit clk, go=1'b1, flag; 
	function void setgo(bit val, bit [31:0] val2, fg);
		go=val;
		flag=fg;
		rose_bus= val2;
	endfunction 
 
	initial forever #5 clk=!clk; 
	sequence q_all_rose; 
		$countones(rose_bus)==32 [->1]; 
	endsequence
 
    generate
       genvar i;
         for (i = 0; i<=31; i++) begin
            always @ (posedge clk) begin 
		      if($rose(my_bus[i])) rose_bus[i]<=1'b1;
		      if (flag) ap_fell: assert(!$fell(my_bus[i])); 
		    end
         end
    endgenerate
	
	ap_allrose: assert property(@(posedge clk) 
			(go, setgo(1'b0, 0, 1)) |->  q_all_rose) setgo(1'b1, 0, 0); 
	
	always @(posedge clk) 
	begin 
		if (!randomize(my_bus) with {$countones(my_bus)==1;} ) 
			`uvm_error("MYERR", "This is a randomize error"); 	
	end 

endmodule 

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us

  • SystemVerilog Assertions Handbook 3rd Edition, 2013 ISBN 878-0-9705394-3-6
  • A Pragmatic Approach to VMM Adoption 2006 ISBN 0-9705394-9-5
  • Using PSL/SUGAR for Formal and Dynamic Verification 2nd Edition, 2004, ISBN 0-9705394-6-0
  • Real Chip Design and Verification Using Verilog and VHDL, 2002 isbn 0-9705394-2-8
  • Component Design by Example ", 2001 ISBN 0-9705394-0-1
  • VHDL Coding Styles and Methodologies, 2nd Edition, 1999 ISBN 0-7923-8474-1
  • VHDL Answers to Frequently Asked Questions, 2nd Edition ISBN 0-7923-8115