Search code examples
testingverilogsystem-verilogverificationsystem-verilog-assertions

Serial Testbenching and assertions with System-Verilog


I have a serial output of a verilog module I'd like to testbench using system-verilog.

The output, called 'SO' will output something like 8'hC6 given the correct serial input 'SI' with a value of say 8'h9A.

Is there an easy way to encode / decode serial IOs without having to explicitly describe each signal?

For example:

assert property @(posedge clk) $rose(EN) |-> ##[1:3] SI ##1 !SI[*2] ##1 SI[*2] ##1 !SI ##1 SI ##1 !SI
                                             ##[1:3] SO[*2] ##1 !SO[*3] ##1 SO[*2] ##1 !SO;

It looks like a jumbled mess and is barely readable. I'd very much like to just write

8'h9A ##[1:3] 8'hC6

but obviously this doesn't work. Any advice or examples would be more than welcome. Thanks in advance.


Solution

  • Try a sequence and refer to IEEE Std 1800-2012 section 16.10 (Local variables):

    sequence seq_serial(logic signal, local logic [7:0] expected);
        byte idx = 7;
        (signal == expected[idx], idx--)[*8];
    endsequence : seq_serial
    
    asrt_si0x9A_so0xC6 : assert property ( @(posedge clk)
        $rose(EN) |-> ##[1:3] seq_serial(SI, 8'h9A) ##[1:3] seq_serial(SO, 8'hC6) );
    

    This is equivalent to the the assertion provided and is more readable.

    Do note the local keyword which will treat expected as a variable rather then a reference and allows you to pass constant (e.g. 8'h9A, 8'hC6) and still allows you pas net references. See IEEE Std 1800-2012 section 16.8.2 (Local variable formal arguments in sequence declarations) for more.

    Here is a simple test bench to prove the assertion. I'm driving SO because I don't have a real DUT and I want to demonstrate both a pass & fail scenario.

    bit EN, clk;
    logic SI,SO;
    logic [7:0] si_var, so_var;
    initial forever #10ns clk++; // clock generator
    default clocking cb @(posedge clk); output #1ns EN,SI,SO; endclocking : cb
    initial begin : test_vector
        si_var = 8'h9A;
        so_var = 8'hC6;
        ##1 cb.EN <= 1;
        ##($urandom_range(2,0)); // rand delay
        foreach(si_var[i]) ##1 cb.SI <= si_var[i];
        ##($urandom_range(2,0)); // rand delay
        foreach(so_var[i]) ##1 cb.SO <= so_var[i];
        ##1 cb.EN <= 0;
    
        /* Now make the assertion fail */
        so_var = 8'hC7; // make fail
        ##3 cb.EN <= 1;
        ##($urandom_range(2,0)); // rand delay
        foreach(si_var[i]) ##1 cb.SI <= si_var[i];
        ##($urandom_range(2,0)); // rand delay
        foreach(so_var[i]) ##1 cb.SO <= so_var[i];
        ##1 cb.EN <= 0;
    
        #10ns; // little delay before finish
        $finish(2);
    end : test_vector