硅芯思见:SVA中的形式参数

在一些设计中有时信号需要使用相似的属性结构,仅仅只是采样时钟不同而已,如果针对每个时钟将属性重复编写,代码将会冗繁,为此SVA中可以在属性中增加形参,从而可以讲不通的参数传入属性中实现基于不同频率的属性结构。其实在形参中,不止可以将时钟作为参数传入属性中,属性结构中基本所有的相关变量都可以通过形参传入,例如各种时序延迟信息等,这种特性也使得属性的构建更加灵活、更加具有普适性。



【示例】
`timescale 1 ns / 1 ps
module top_tb;
logic clk0,clk1;
logic sig0,sig1,sig2,sig3;

initial begin
    clk0 = 1'b0;clk1 = 1'b0;
    fork
        forever #1 clk0 = ~clk0;
        forever #2 clk1 = ~clk1;
    join
end
// p1 stimulus
initial begin
       sig0 = 1'b0;sig1 = 1'b0;
       sig2 = 1'b0;sig3 = 1'b0;
    #2 sig0 = 1'b1;
    #2 sig1 = 1'b1;sig2 = 1'b1;sig0 = 1'b0;
    #2 sig1 = 1'b0;
    #2 sig3 = 1'b1;sig2 = 1'b0;
    #4 $stop;
end
// property
property p(clk,sig0,sig1);
    @(posedge clk) $rose(sig0) |-> ##1 sig1;
endproperty  // p
// assertion
a0 : assert property(p(clk0,sig0,sig1)) $display("@%0t | p0 : PASSED!",$time);
     else $display("@%0t | p0 : FAILED!",$time);
a1 : assert property(p(clk1,sig2,sig3)) $display("@%0t | p0 : PASSED!",$time);
     else $display("@%0t | p0 : FAILED!",$time);     
endmodule // top_tb
【仿真结果】

示例中,断言a0的时钟频率是a1的两倍,sig0sig1sig2sig3信号的位宽也不一样,但是他们使用的属性结构是完全一样的,如果采用传统的方式分别编写属性实现,那么代码量明显会增多。当采用SVA的参数化特性之后,就可以实现属性的复用,通过将上述要检查的参数在断言时传入到属性中,即可实现属性结构的复用。

除了可以针对不同参数使用相似属性结构实现对不同信号的检测外,带有参数的属性还可以结合其他结构实现对于多位宽信号的检查。例如在一些设计中,会存在很多总线类信号,在属性描述中不能使用for循环结构遍历指定总线中的每一位,也不能使用generate结构,那么应该如何对总线中的每一位单独进行属性检查呢?当然可以单独针对每一位编写各自的属性结构,但是这种方式对于几位宽的总线信号可能还可行,但是如果要对几十位几百位宽的总线信号单独编写相同的属性,工作量将是巨大的,就算可以通过特定的脚本生成对应的代码,但是这样的代码可读性和可维护性也不好。为此,可以通过SVA中的参数化属性实现。这样的功能。



【示例】
`timescale 1 ns / 1 ps
module top_tb;
logic        clk;
logic       sig0;
logic [2:0] sig1;


initial begin
    clk = 1'b0;
    forever #1 clk = ~clk;
end

initial begin
       sig0 = 1'b0;   sig1 = 'b000;
    #2 sig0 = 1'b1;#2 sig1 = 'b001;sig0 = 1'b0;#2 sig1 = 'b000;
    #2 sig0 = 1'b1;#2 sig1 = 'b010;sig0 = 1'b0;#2 sig1 = 'b000;
    #2 sig0 = 1'b1;#2 sig1 = 'b100;sig0 = 1'b0;#2 sig1 = 'b000;
    #2 sig0 = 1'b1;#2 sig1 = 'b111;sig0 = 1'b0;#2 sig1 = 'b000;
    #4 $stop;
end
// property
property p(num);
    @(posedge clk) $rose(sig0) |-> ##1 sig1[num];
endproperty  // p
// assertion
genvar i;
generate for(i = 0;i < 3;i = i +1) begin : loop
    a : assert property(p(i)) $display("@%0t | p : PASSED!",$time);
        else $display("@%0t | p : FAILED!",$time);  
end
endgenerate 
endmodule // top_tb

【仿真结果】

示例中,通过定义具有参数的属性,结合generate-for结构将索引值传递到属性中,从而实现了对多位总线信号中每一位使用相同的属性检查结构。这里需要注意不是讲一个assert执行了很多遍,而是生成了很多个assertion。其实不止属性可以使用参数,序列也可以使用形式参数。



【示例】
`timescale 1 ns / 1 ps
module top_tb;
logic clk;
logic sig0,sig1;

initial begin
    clk = 'b0;
    forever #1 clk = ~clk;
end 

initial begin
       sig0 = 1'b0;sig1 = 1'b0;
    #2 sig0 = 1'b1;#2 sig1 = 1'b1;
       sig0 = 1'b0;#2 sig1 = 1'b0;
    #4 $stop;
end
// sequence
sequence s(logic sig);
    sig;
endsequence // s
// property
property p(clk,sig0,sig1);
    @(posedge clk) $rose(sig0) |-> ##1 s(sig1);
endproperty // p
// assertion
a : assert property(p(clk,sig0,sig1)) $display("@%0t | p : PASSED!",$time);
    else $display("@%0t | p : FAILED!",$time);  
endmodule // top_tb
【仿真结果】 

可见参数通过assert传递给property,再通过property传递给sequence。在序列中我们给形参指定了类型为logic,其实也可以不用指定,不指定时其类型取决于实际传入参数的类型。形参不仅可以在属性和序列中传递一般信号外,断言中的参数传递还有一个比较特殊的地方,那就是可以将“采样边沿”作为参数进行传递,对上述实例进行修改如下。



【示例】
`timescale 1 ns / 1 ps
module top_tb;
logic clk;
logic sig0,sig1;

initial begin
    clk = 'b0;
    forever #1 clk = ~clk;
end 

initial begin
       sig0 = 1'b0;sig1 = 1'b0;
    #2 sig0 = 1'b1;#2 sig1 = 1'b1;
       sig0 = 1'b0;#2 sig1 = 1'b0;
    #4 $stop;
end
// sequence
sequence s(logic sig);
    sig;
endsequence // s
// property
property p(posclk,sig0,sig1);
    @(posclk) $rose(sig0) |-> ##1 s(sig1);
endproperty // p
// assertion
a : assert property(p(posedge clk,sig0,sig1)) $display("@%0t | p : PASSED!",$time);
    else $display("@%0t | p : FAILED!",$time);  
endmodule // top_tb

形参除了上述用途外,还可以在定义形参时,给形参赋以默认值。


【示例】
`timescale 1 ns / 1 ps
module top_tb;
logic clk;
logic sig0,sig1;
logic enable;


initial begin
    clk = 1'b0;
    forever #1 clk = ~clk;
end

initial begin
       sig0 = 1'b0;   sig1 = 1'b0;enable = 1'b0;
    #2 sig0 = 1'b1;#2 sig1 = 1'b1;
    #2 sig0 = 1'b0;#2 sig1 = 1'b0;enable = 1'b1;
    #2 sig0 = 1'b1;#2 sig1 = 1'b1;
    #4 $stop;
end
// property
property p(clk,enable = 1'b1,sig0,sig1);
    @(posedge clk) enable |-> $rose(sig0) |-> ##1 sig1;
endproperty  // p
// assertion
a0 : assert property(p(clk,,sig0,sig1)) $display("@%0t | p0 : PASSED!",$time);
     else $display("@%0t | p0 : FAILED!",$time); 
a1 : assert property(p(clk,enable,sig0,sig1)) $display("@%0t | p1 : PASSED!",$time);
     else $display("@%0t | p1 : FAILED!",$time);      
endmodule // top_tb 
【仿真结果】


示例中,属性形参列表中的enable有默认值“1b1”,a0中给p传递参数时并没有指定对应的enable的值(但是在assert时,对应的参数列表中空出了对应的参数位置),所以属性中的enable采用形参列表中指定的默认值,所以仿真开始后即开始对a0中的属性进行检查。而a1中使用了tb中指定的enable,该参数传递给属性的形参,此时属性中的enablea1中指定的enable决定,因为此时传递的enable1,此时属性中的“$rose(sig0) |-> ##1 sig1”进行对应的检查,示例中,enable6ns时为真后,才开始属性表达式的检查计算。

通过上述示例,我们可以将构建具有形参的属性或者sequence的流程归纳如下:



全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务