Serial Testbenching and assertions with System-Verilog

纵饮孤独 提交于 2019-12-21 05:36:07

问题


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.


回答1:


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



回答2:


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.



来源:https://stackoverflow.com/questions/17037889/serial-testbenching-and-assertions-with-system-verilog

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!