APB write cycle assertion

I am trying to write a assertion for APB write cycle with no wait states. Here is what i have written, the assertion doesnt seem to pass at all. Can any one tell me what is wrong here?



// Code your testbench here
// or browse Examples

import uvm_pkg::*; 
`include "uvm_macros.svh" 

module top; 
  bit pclk,pwrite,psel,penable,pready;
  bit [7:0] pwdata,paddr;
  
  default clocking @(posedge pclk); endclocking
 initial forever #10 pclk=!pclk;
  
 
 property p1;
   
   @(posedge pclk) $rose (pwrite && psel) |-> ($stable(paddr && pwdata)[*2]) ##1 $rose (penable && pready) ##1 $fell (pwrite && psel && penable && pready);
endproperty
 
 
  assert property (p1) $display ("Assertion passed",$time);
    
    
    
    
            initial begin
              $dumpfile ("hello.vcd");
              $dumpvars (0,top);
            end
              
 initial begin 
   repeat(100) begin 
     repeat(1) @(posedge pclk) #1;  
     if (!randomize(pwrite,psel,penable,pready) with
         {pwrite dist    {1'b1:=1,1'b0:=1};
          psel dist { 1'b1:=1,1'b0:=1};
          penable dist { 1'b1:=1,1'b0:=1};
          pready dist { 1'b1:=1,1'b0:=1};
         }) `uvm_error("MYERR", "This is a randomize error");
      repeat (2) @ (posedge pclk) #1;
     if (!randomize(paddr,pwdata))
       `uvm_error("MYERR", "This is a randomize error");
        end 
   $stop;
 end 
endmodule

In reply to rag123:
As you know, I generally use the randomize with weighted probabilities.
It is tricky to get what you need when you have complex scenarios with
stuff like [*2] and $rose and $fell of a combination of signals.
To do that I generally play with the weights, and avoid doing things like


 if (!randomize(..);
 repeat (2) @ (posedge pclk) #1; // <-- avoid 
 if (!randomize(..); 

// *********
// instead, fix your constraints in one shot
 if (!randomize(pwrite,psel,penable,pready) with
         {pwrite dist    {1'b1:=1,1'b0:=1};
          psel dist { 1'b1:=1,1'b0:=1};
          penable dist { 1'b1:=1,1'b0:=1};
          pready dist { 1'b1:=1,1'b0:=1};
         }) `uvm_error("MYERR", "This is a randomize error");
 // repeat (2) @ (posedge pclk) #1;
 if (!randomize(paddr,pwdata)  with
          {paddr  dist {1'b1 :=5, 1'b0:=1};  // Play with the weights
           pwdata dist {1'b1:=5, 1'b0:= 1};})
       `uvm_error("MYERR", "This is a randomize error");
 

I played with the weights of all the variables and I got failures.
There are too many variables and conditions to get things to work by change thru randomization.
You’ll need to create directed tests, maybe with some randomization.
It’s hard to win the pick-6 lottery!
:)

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact http://cvcblr.com/home.html
** SVA Handbook 4th Edition, 2016 ISBN 978-1518681448

  1. SVA Package: Dynamic and range delays and repeats SVA: Package for dynamic and range delays and repeats | Verification Academy
  2. Free books: Component Design by Example FREE BOOK: Component Design by Example … A Step-by-Step Process Using VHDL with UART as Vehicle | Verification Academy
    Real Chip Design and Verification Using Verilog and VHDL($3) https://rb.gy/cwy7nb
  3. Papers:

In reply to ben@SystemVerilog.us:

Thanks Ben :) I understand there are lot of variables involved. I will write a directed testbench. Can you review the assertion i wrote and give feedback? I have attached the image.

In reply to rag123:
Spec: ARM_AMBA3_APB.pdf
You are attempting to write an assertion for a Write transfer with no wait states. However the spec states that there are two types of write transfers:
• With no wait states
• With wait states.
The assertion you wrote, though incorrect, still needs a term in the antecedent to specify that this is a no wait transfer, else it will fail if more than one state.


 @(posedge pclk) no_wait_write ##0 // generated by the testbench or slave
              $rose (pwrite && psel) |->  ##1   // 1
              $stable(paddr && pwdata)    ##0   // 2  **ERROR in construct, see next posts
              $rose (penable && pready)   ##1   // 3
              pwrite && !psel && !penable);     // 4

The figure below shows the timing. The term no_wait_write ##0 is missing in the diagram.

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact http://cvcblr.com/home.html
** SVA Handbook 4th Edition, 2016 ISBN 978-1518681448

  1. SVA Package: Dynamic and range delays and repeats SVA: Package for dynamic and range delays and repeats - SystemVerilog - Verification Academy
  2. Free books: Component Design by Example https://rb.gy/9tcbhl
    Real Chip Design and Verification Using Verilog and VHDL($3) Amazon.com
  3. Papers:

In reply to ben@SystemVerilog.us:

Hi Ben,

Thanks for the reply. Yes there are two cases one with wait state and one without wait state.


@(posedge pclk) no_wait_write ##0 // generated by the testbench or slave
              $rose (pwrite && psel) |->  ##1   // 1
              $stable(paddr && pwdata)    ##0   // 2 
              $rose (penable && pready)   ##1   // 3
              pwrite && !psel && !penable);     // 4


$stable(paddr && pwdata) // For this line
Are we not expecting the paddr and pwdata to be stable for 2 clks?

In reply to rag123:

  • I made a mistake in $stable(paddr && pwdata) because they are vectors, and you do to want to AND the vectors and then check for stability. Should be
    $stable(paddr) && $stable(pwdata).
  • If you look at the timing, addr@T2 == addr@T3, i.e., thus stable
    The $stable is tested at T3, the cycle after the rose in the antecedent.
    I see 2 clocks in the stabibilty, one at the $rose (at t2) and other in the next cycle at T3.

ap: assert property( 
           @(posedge pclk) now_waite_write ##0  
              $rose (pwrite && psel) |->  ##1   // 1 $rose is at T2 
              $stable(paddr) && $stable(pwdata) ##0    / 2 at T3
              // addr@T2 == addr@T3, i.e., thus stable 
              $rose (penable && pready) ##1                  // 3  at $rose at T3
              pwrite && !psel && !penable);                  // 4  at T4

In reply to ben@SystemVerilog.us:

Thanks a lot Ben :) I also tried with Wait states. can you let me know if this is correct?



sequence s1;
    $rose (pwrite && psel) |-> ##1 (pwrite && psel) until with pready;
  endsequence
  
  sequence s2;
    $stable ((paddr) && $stable (pwdata)) until with pready;
  endsequence
  
  sequence s3;
    $rose (penable) ##1 penable until with pready
  endsequence
  

property p2;
    @(posedge pclk)    
    s1 |=> s2 |=> s3 ##1 pwrite && !psel && !penable
  endproperty

assert property (p2);

In reply to rag123:

  • First of all, I am NOT a fan of multiple sequence declarations unless each sequence is complex and serves a specific function, or if I need an endpoint.
  • I am also NOT a fan of multiple implication operators because of vacuity.
 sq1 |=> sq2 |=> sq3
// If sq2 is not a match, the property is vacuous 
  • Your sequence s1: sequenceA |-> sequenceB IS NOT A sequence, it is a PROPERTY. It cannot be declared in a sequence declaration
  • Use a compiler/simulator to test your code
    See https://www.edaplayground.com/
  • SPECS says “PSELx, also goes LOW unless the transfer is to be followed immediately by another transfer to the same peripheral”. That is not handled here.
// in ( pwrite && !psel && !penable), there is a need to
// detect another xfr to another peripheral for the !psel
// My take 
ap_ahb_write_with_without_wait: assert property( 
   $rose (pwrite && psel) |-> !penable ##1  
       $rose (penable) ##0 
       $stable ((paddr) && $stable (pwdata)) until_with pready ##1
       pwrite && !psel && !penable // !psel is questionable here 
 );  

In reply to ben@SystemVerilog.us:

Hi Ben,

Thanks. when i compiled it is failing on until_with


Error-[SE] Syntax error
  Following verilog source has syntax error :
  "testbench.sv", 18: token is 'until_with'
     $stable ((paddr) && $stable (pwdata)) until_with pready ##1 pwrite && 
  !psel && !penable);

In reply to rag123:

Actually i realized that, the issue is seen only on one simulator.

In reply to rag123:
Works with my simulator. As you mentioned, this is a tool issue, and we don’t discuss tools here. Note

$rose(req) |=> busy until_with ready); // Enhanced readability, and Identical to
// $rose(req) |=> busy[*0:$] ##1 ready && busy; // equivalent property expression
// Thus, you can rewrite as  
p_ahb_write_with_without_wait2: assert property( 
  $rose (pwrite && psel) |-> !penable ##1  
      $rose (penable) ##0 
      $stable ((paddr) && $stable (pwdata))[*0:$] ##1 
      pready && $stable ((paddr) && $stable (pwdata)) ##1
      pwrite && !psel && !penable // !psel is questionable here 
 );  
 
// FOR documentation 
ap_ahb_write_with_without_wait: assert property( 
   $rose (pwrite && psel) |-> !penable ##1  
       $rose (penable) ##0 
       $stable ((paddr) && $stable (pwdata)) until_with pready ##1
       pwrite && !psel && !penable // !psel is questionable here 
 );