Question

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.

Was it helpful?

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

OTHER TIPS

You usually don't use assertions to describe checks on data items, but on control signals. What you need in this case is to collect your whole input stream into a 16bit vector, collect you whole output stream and check that what you got on the SO line matches what you're supposed to get (some transformation of what was on the SI line).

My SystemVerilog is rusty, but I'll give you a quick example of what I mean. Be aware that it's not compilable.

// collect input
always @(posedge clk) begin
  if en == 1 begin
    collect_input();
  end
end

logic[7:0] si;

task collect_input();
  for i from 0 to 7 begin
    si[i] = SI;  // take care of endianness here, might be si[7-i];
  end
endtask


// collect output
...

logic[7:0] so;

...

collect_output();
  for ...

  // after collecting so, check that it's correct
  if so != transform(si) begin
    $error("wrong output data");
  end
endtask

Hope it gives you an idea.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top