通常的工作流程如下:(1)根据设计,给出设计的约束。如果是Timing方面的约束,为更好的描述,可以使用相关的描述工具如Timing designer来进行设计,完成后,使用语言来描述这些设计约束;(2)将这些设计约束用SystemVerilog Assertions语言来描述。通常有两种方法来将SVA校验器连接到设计中。1是在模块定义中内建或者内联检验器。2是将检验器与模块,模块的实例或者一个模块的多个实例绑定。
下面分别给出两个例子:
例子1:内联在模块中的SVA
module inline(clk, a, b, d1, d2, d);
input logic clk, a, b;
input logic [7:0] d1, d2;
output logic [7:0] d;
always @(posedge clk) begin
if (a)
d <= d1;
else
d <= d2;
end
property p_mutex;
@(posedge clk) not (a && b);
endproperty
a_mutex: assert property(p_mutex );
endmodule
在这个例子中,就是将SVA检验器和具体设计的模块绑定在一起。这种做法,不好的地方就是将RTL Code和Assertion Checker混合在一起。Assertion Checker是不能综合的。于是,检验完毕后还需要将这些检验的代码去掉。
例子2:分别有两个模块,一个是RTL Code,另一个是SVA检验器模块。
module mutex(clk, a, b, d1, d2, d);
input logic clk, a, b;
input logic [7:0] d1, d2;
output logic [7:0] d;
always @(posedge clk) begin
if (a)
d <= d1;
else
d <= d2;
end
endmodule
这个就是SVA检验器模块。
module mutex_chk(a, b, clk);
input logic a, b, clk;
property p_mutex;
@(posedge clk) not (a && b);
endproperty
a_mutex: assert property(p_mutex);
endmodule
检验器模块如果是一个独立的模块时,就涉及一个如何与设计中任何的模块或者实例绑定的问题,可以采用的绑定方法如下:(1)同其他RTL模块一样,实例化这个Monitor模块; (2)利用SVA中的bind语句,实际完成与任何模块的绑定。
下面分别对这两种方法进行介绍:
第一种方法:同其他RTL模块一样,实例化这个Monitor模块。
`timescale 1ns/100ps
module harness;
parameter FAST_PERIOD = 10;
reg Clock;
reg Rst_n;
wire [7:0] Mpi_data;
wire [5:0] Mpi_addr ;
wire Mpi_cs_n;
wire Mpi_rw;
//
// Clock Stimulus generation.
//
initial begin
Clock = 0;
forever begin
#(FAST_PERIOD/2) Clock = ~ Clock;
end
end
//
// Reset Stimulus generation.
//
initial begin
Rst_n = 1;
# FAST_PERIOD
Rst_n = 0;
# (5 * FAST_PERIOD) Rst_n = 1;
end
//
// MPI Bus Functional Module(BFM).
// 这个是总线功能模块
uP_BFM inst_BFM (
.uP_data(Mpi_data), .uP_addr(Mpi_addr),
.uP_cs_n(Mpi_cs_n), .uP_rw(Mpi_rw));
//
// Design Module(DUT)
// 这个是被测试模块
MPI u_MPI (
.Clock(Clock), .Rst_n(Rst_n), .Mpi_data(Mpi_data),
.Mpi_addr(Mpi_addr), .Mpi_cs_n(Mpi_cs_n), .Mpi_rw(Mpi_rw)) ;
//
// Assertion-based Monitor.
// 这个是Monitor模块
MPI_monitor monitor(
.Clock(Clock), .Rst_n(Rst_n), .Mpi_data(Mpi_data), .Mpi_addr(Mpi_addr), .Mpi_cs_n(Mpi_cs_n), .Mpi_rw(Mpi_rw));
endmodule
这种方法面临的一个问题是:有的时候无法将深层次模块的信号引出来。上面的例子比较简单,如果遇到复杂的情况,比如有很多的设计层次的话,难以对比较深层 次的模块信号进行检查。
第2种方法:是采用绑定的方法 绑定的语法介绍如下:
bind <module_name or instance_name>
<checker name> <checker instance name> <design signals>;
第一个参数是要绑定的模块名或者模块的实例名,第2个参数是Monitor的名字,
然后跟Monitor的实例,最后是信号的一个对接。 例如:和上面的做法不同的是在Monitor模块中加入下面的Bind语句。
// Bind with the DUT.
bind MPI MPI_Monitor monitor0
(.Clock(Clock), .Rst_n(Rst_n), .Mpi_data(Mpi_data), .Mpi_addr(Mpi_addr), .Mpi_cs_n(Mpi_cs_n), .Mpi_rw(Mpi_rw));
这个例子中,就使用了绑定的方法,将这个MPI_Monitor模块的monitor0实例绑定到MPI模块去,最后描述的是信号的一个对接。 当你启动支持Assertion的仿真工具的时候,就可以使用Assertions啦。哈哈