一、SystemVerilog断言
SVA可以在设计中创建时序断言,在整个仿真过程中都是有效的,仿真器会跟踪哪些断言被激活,来在此基础上收集功能覆盖率的数据。
1、立即断言
测试平台的过程代码可以检查待测设计的信号值和测试平台的信号值,并且在存在问题的时候采取相应的行动。
使用if语句检查一个信号
bus.cb.request <= 1;
repeat(2) @bus.cb;
if(bus.cb.grant != 2'b01)
$display("ERROR, grant != 1");
...
简单的立即断言
bus.cb.request <= 1;
repeat(2) @bus.cb;
al: assert(bus.cb.grant == 2'b01); //成功,继续执行;不符合预期,则仿真器给出错误信息
...
2、定制断言行为
一个立即断言有可选的then和else分句。可以修改默认的错误信息。SystemVerilog有四个输出消息的函数:$info, $warning, $error, $fatal
在立即断言中创建一个定制的错误信息
al: assert(bus.cb.grant == 2'b01);
else $error("XXXXXX");
使用then子句记录断言何时成功完成
al: assert(bus.cb.grant == 2'b01)
grant_received++;
else
$error("XXXXXX");
3、并发断言
可以认为它是连续运行的模块,为整个仿真过程检查信号的值,你需要在断言内指定一个采样时钟。
检查X/Z的并发断言
interface arb_if(input bit clk);
logic[1:0] grant, request;
logic rst;
property request_2state;
@(postedge clk) disable iff(rst); //request信号除了在复位期间,其他任何时候都不能是x或者z
$isunknown(request) == 0; //确保没有z或者x值存在
endproperty
assert_request_2state: assert property(request_2state);
endinterface
4、断言的进一步探讨
在接口中也可以使用断言,这样接口不仅可以传送信号值也可以检查协议的正确性,有一本《SystemVerilog Assertion》的书籍可以一看。
二、四端口的ATM路由器
加大难度,真正的设计具有
更多的输入和输出,如四端口的ATM(Asynchronous Transfer Mode,异步传输模式)路由器。
1、使用端口的ATM路由器
未使用接口类型的ATM路由器模型首部
2、使用端口的ATM顶层网单
未使用接口的顶层网单
module top;
bit clk;
always # 5 clk= ! clk;
wire Rx_clk_0,Rx_clk_1,Rx_clk_2,Rx_clk_3,
Rx_soc_0,Rx_soc_1,Rx_soc_2,Rx_soc_3,
Rx_en_0,Rx_en_1,Rx_en_2,Rx_en_3,
Rx_clav_0,Rx_clav_1,Rx_clav_2,Rx_clav_3,
Tx_clk_o,Tx_clk_1,Tx_clk_2,Tx_clk_3,
Tx_soc_0,Tx_soc_1,Tx_soc_2,Tx_soc_3,
Tx_en_0,Tx_en_1,Tx_en_2,Tx_en_3,
Tx_clav_0,Tx_clav_1,Tx_clav_2,Tx_clav_3,rst;
wire[7:0] Rx_data_0,Rx_data_1,Rx_data_2,Rx_data_3,
Tx_data_o,Tx_data_1, Tx_data_2,Tx_data_3;
atm_router al(Rx_clk_0,Rx_clk_1,Rx_clk_2,Rx_clk_3,
Rx_data_0,Rx_data_1,Rx_data_2,Rx_data_3,
Rx_soc_o,Rx_soc_1,Rx_soc_2,Rx_soc_3,
Rx_en_0,Rx_en_1,Rx_.en_2,Rx_en_3,
Rx_clav_0,Rx_clav_1,Rx_clav_2,Rx_clav_3,
Tx_olk_0,Tx_clk_1,Tx_clk_2,Tx__clk_3,
Tx_data_0,Tx_data_1, Tx_data_2,Tx_data_3,
Tx_soc_0, Tx_soc_1,Tx_soc_2,Tx_soc_3,
Tx_en_0,Tx_en_1,Tx_en_2,Tx_en_3,
Tx_clav_0,Tx_clav_1,Tx_clav_2,Tx_clav_3,
rst,clk);
test t1(Rx_clk_0,Rx_clk_1,Rx_clk_2,Rx_clx_3,
Rx_data_o,Rx_data_1,Rx_data_2,Rx_data_3,
Rx_soc_0,Rx_soc_1,Rx_soc_2,Rx_soc_3,
Rx_en_0,Rx_en_1,Rx_en_2,Rx_en_3,
Rx_clav_0,Rx_clav_1,Rx_clav_2,Rx_clav_3,
Tx_clk_0,Tx_clk_1,Tx_clk_2,Tx_clk_3,
Tx_data_0, Tx_data_1,Tx_data_2,Tx_data_3,
Tx_soc_0,Tx_soc_1, Tx_soc_2, Tx_soc_3,
Tx_en_0,Tx_en_1,Tx_en_2,Tx_en_3,
Tx_clav_0,Tx_clav_1,Tx_clav_2,Tx_clav_3,
rst,clk);
endmodule
使用端口的测试平台
module test (
// 4 x Level 1 Utopia ATM layer Rx Interfaces
Rx_clk_0,Rx_clk__1,Rx_clk_2,Rx_clk_3,
Rx_data_0,Rx_data_1,Rx_data_2,Rx_data_3,
Rx_soc_0,Rx_soc_1,Rx_soc_2,Rx_soc_3,
Rx_en_0,Rx_en_1,Rx_en_2,Rx_en_3,
Rx_clav_0,Rx_clav_1,Rx_clav_2,Rx_clav_3,
//4 x Level 1 Utopia ATM layer Tx Interfaces
Tx_clk_0,Tx__clk_1,Tx_clk_2,Tx_clk_3,
Tx_data_0,Tx_data_1,Tx_data_2,Tx_data_3,
Tx_soc_0,Tx_soc_1,Tx_soc_2,Tx_soc_3,
Tx_en_0,Tx_en_1,Tx_en_2,Tx_en_3,
Tx_clav_0,Tx_clav_1,Tx_clav_2,Tx_clav_3,
//其他控制信号
rst,clk);
//4 x Level 1 utopia Rx Interfaces
input Rox_clk_0,Rx_clk_l,Rx_clk_2,Rx_clk_3;
output [7:0] Rx_data_0,Rx_data_1,Rx_data_2,Rx_data_3;
reg [7:0] Rx_data_0,Rx_data_1,Rx_data_2,Rx_data_3;
output Rx_soc_0,Rx_soc_1,Rx_soc_2,Rx_soc_3;
reg Rx_soc_0,Rx_soc_1,Rx_soc_2,Rx_soc_3;
input Rx_en_0,Rx_en_1,Rx_en_2,Rx_en_3;
output Rx_clav_0,Rx_clav_1,Rx_clav_2,Rx_clav_3;
reg Rx_clav_0,Rx_clav_1,Rx_clav_2,Rx_clav_3;
// 4 x Level 1 Utopia Tx Interfaces
input Tx_clk_0,Tx_clk_1, Tx_clk_2,Tx_clk_3;
input [7:0] Tx_data_0,Tx_data_1,Tx_data_2,Tx_data_3;
input Tx_soc_0,Tx_soc_1,Tx_soc_2,Tx_soc_3;
input Tx_en_0,Tx_en_1,Tx_en_2,Tx_en_3;
output Tx_clav_0,Tx_clav_1, Tx_clav_2,Tx_clav_3;
reg Tx_clav_0,Tx_clav_1,Tx_clav_2,Tx_clav_3;
//其他控制信号
output rst;
reg rst;
input clk;
initial begin
//复位设备
rst <= 1;
Rx_data_0 <= 0;
...
end
endmodule
没有使用接口的多输入多输出的设备,由此可见,代码及其繁琐冗余!!!
3、使用接口简化连接
测试平台——使用接口的路由器框图,其中信号被分组装进接口
4、ATM接口
使用了modport和时钟块的Rx接口
interface Rx_if(input logic clk);
logic[7:0] data;
logic soc,en,clav,rclk;
clocking cb @(postedge clk);
output data,soc,clav; //方向是相对测试平台的
input en;
endclocking : cb
modport DUT(output en,rclk,
input data,soc,clav);
modport TB(clocking cb);
endinterface : Rx_if
使用modport和时钟块的Tx接口
interface Tx_if(input logic clk);
logic[7:0] data;
logic soc,en,clav,tclk;
clocking cb @(postedge clk);
input data,soc,en; //方向是相对测试平台的
output clav;
endclocking : cb
modport DUT(output data,soc,en,tclk,
input clk,clav);
modport TB(clocking cb);
endinterface : tx_if
5、使用接口的ATM路由器模型
接口中使用modport的ATM路由器模型
module atm_router(Rx_if.DUT Rx0,Rx1,Rx2,Rx3,
Tx_if.DUT Tx0,Tx1,Tx2,Tx3,
input logic clk,rst);
...
endmodule
6、使用接口的ATM顶层网单
使用接口的顶层网单
module top;
bit clk,rst;
always # 5 clk = !clk;
Rx_if Rx0(clk),Rx1(clk),Rx2(clk),Rx3(clk);
Tx_if Tx0(clk),Tx1(clk),Tx2(clk),Tx3(clk);
atm_router al(Rx0,Rx1,Rx2,Rx3,Tx0,Tx1,Tx2,Tx3,clk,rst);
test t1(Rx0,Rx1,Rx2,Rx3,Tx0,Tx1,Tx2,Tx3,clk,rst);
endmodule : top
7、使用接口的ATM测试平台
接口中使用时钟块的测试平台
program test(Rx_if.TB Rx0,Rx1,Rx2,Rx3,
Tx_if.TB Tx0,Tx1,Tx2,Tx3,
input logic clk,
output logic rst);
bit[7:0] bytes[ATM_CELL_SIZE];
initial begin
rst <= 1;
Rx0.cb.data <= 0;
...
received_cell0();
...
end
task receive_cell0();
@(Tx0.cb);
Tx0.cb.clav <= 1; //准备接收
wait(Tx0.cb.soc == 1); //等待信元的开始
for(int i = 0; i < ATM_CELL_SIZE; i++) begin
wait(Tx0.cb.en == 0); //等待使能信号
@(TX0.cb);
bytes[i] = Tx0.cb.data;
@(TX0.cb);
Tx0.cb.clav <= 0; //释放流控信号
end
endtask : receive_cell0
endprogram : test
三、ref端口的方向
ref端口其实是对变量(不能是net)的引用,它的值时该变量最后一次赋的值。如果讲一个变量连接到多个ref端口,就可能产生竞争,因为多个模块的端口都可能更新同一个变量。
四、仿真的结束
仿真在程序块中的最后一个initial块结束时结束,其实是隐形地调用¥exit以标志程序的结束。所有的程序块都退出了,$finish函数的隐形调用也就结束了。
仿真并没有完全结束。模块或者程序块可以定义一个或者多个finial块来执行仿真器退出前的代码,用来放置清理任务的代码。在finial块中不能调度事件,或含有任何时延信息。
finial块
program test;
int errors,warning;
initial begin
...
end
finial
$display("test done with %0d errors and %0d warnings", errors,warnings);
endprogram