1、DUT(Device Under Test)
interface router_IO(input bit clock);
logic reset_n;
logic [15:0] din;
logic [15:0] frame_n;
logic [15:0] valid_n;
logic [15:0] dout;
logic [15:0] busy_n;
logic [15:0] valido_n;
logic [15:0] frameo_n;
clocking cb @ (posedge clock)
default input #1 output #1;
outpur reset_n;
output din;
output frame_n;
output valid_n;
input dout;
input busy_n;
input valido_n;
input frameo_n;
endclocking
modport TB(clocking cb,output reset_n);
endinterface
program automatic router_test(router_IO.TB router);
//develop test code in initial block;
initial begin
$vcdpluson; //Dumping waveform file control
//$display("Hello world");
end
initial begin
reset();
end
task reset();
router.resetn <= 1'b0;
router.cb.frame_n <= 16'hffff;
router.cb.valid_n <= ~('b0);
##2 router.cb.reset_n <= 1'b1;
repeat(15) @(router.cb);
endtask
endprogram
同步信号驱动时候用非阻塞赋值。
2、语法简介
program
…
endprogram将initial中的begin…end放到其中,作为一个测试案例test case。
测试代码都是放在program block中,program例化在顶层的中top-level harness
结构如下:
//root global variables
//`include files
program [automatic] name(interface);
//`include files
//program global variables
initial begin
//local variables
//top-level tset code
end
task task_name();
//local variable
//code
endtask
endprogram
具体实例如下:
program automatic router_test(router_IO.TB router);
//develop test code in initial block;
initial begin
$vcdpluson; //Dumping waveform file control
//$display("Hello world");
end
initial begin
reset();
end
task reset();
router.resetn <= 1'b0;
router.cb.frame_n <= 16'hffff;
router.cb.valid_n <= ~('b0);
##2 router.cb.reset_n <= 1'b1;
repeat(15) @(router.cb);
endtask
endprogram
module router_test_top;
router_IO top_io(SystemClock); //类似声明端口interface
test t(top_io); //将端口接到case中
router dut( //接到待测试模块
.reset_n(top_io.reset_n),
.clock(top_io.clock),
. ...(top_io. )
);
endmodule
//做一个interface,再把dut连接到interface上,再把interface传到test program中,在test program中其实就是对interface做驱动
DUT连接到interface,首先dut传到testcase,testcase再去驱动interface,interface再去驱动dut。
数据类型
二值逻辑是“0”和“1”,四值逻辑多了“x”和“z”,二值逻辑的初始值是0,把“x”、“z”的四值逻辑赋值给二值逻辑,那就是“0”
bit是二值逻辑,无符号数
eg:bit flag;
bit [7:0] a = 8’b1;
二值逻辑的占用空间变成四值逻辑的一半,可以减少占用的内存,可以提高存取速度。
另一个二值逻辑是byte,8位有符号数
shortint是16位有符号数
int是32位有符号数
longint是64位有符号数
real是二值逻辑,类似double
shortreal 类似于float
eg:
real alpha = 100.0, coverage_result;
coverage_result = $get_coverage(); //取功能覆盖率的值
if(coverage_result==100.0)…;
四值逻辑,如果不赋初值,那么初值就是x
reg是四值逻辑
logic代替了reg和wire,可以用于连续赋值,灵活
integer是一个32位的有符号数
time是一个64位的无符号数,是做仿真时间用的
eg:
integer a = -100, b;
time current_time;
b = -a;
current_time = $time; //返回仿真时间
if(current_time>=100ms) ...
string是一个字符串
数组
fixed- size arrays是固定数组
type array_name[size] [=initial_value];
eg:
integer numbers[5]; //array of 5 integers,indexed 0-4
int b[2] = `{3,7}; //bit[0]=3, bit[1]=7
int c[2][3] = `{{3,7,1},{5,1,9}};
byte d[7][2] = `{default:-1}; //all elements = -1
bit[31:0] a[2][3] = c; //array copy
dynamic arrays:动态数组
type array_name[] [=initial_value]; 只能使一维数组
Queues:队列
type array_name[$] [=initial_value];
不需要分配空间Associative Array:联合数组
type array_name[index_type];
type array_name[*];
数组的循环:foreach
program
initial begin
int data[]; //动态数组
data = new[7]; //为数组分配7个空间
foreach(data[i]) begin
data[i] = 255>>i;
$display("data[%0d]=%0d",i,data[i]);
end
$diplay("sum of array content = %0d",data.sum());
end
endprogram
function array_type[$] array.find() with (expression)
将满足表达式的结果,压入到队列中
function int_or_index_type[$] array.find_index with (expression)
压缩索引号
item可以告诉队列中每个元素的值
eg:
program test;
bit [7:0] SQ_array[$] = {2,1,8,3,5};
bit [7:0] SQ[$];
int idx[$];
SQ = SQ_array.find() with (item > 3);
//SQ[$] contains 5,8
idx = SQ_array.find_index() with (item > 3);
//idx[$] contains 2,4
endprogram
操作符
流程控制task在运行的时候回消耗时间,function不消耗时间
function有输入没有输出,但是有返回值
在function里面不能调用task
在task里面可以调用functionprogram块一般是执行testcase,一般情况下initial begin end就结束了,但是也可以通过$finish去结束它。
subroutine一般是用task function,当endtask或者endfunction就结束,或者return也可以跳出
Loop循环,当end和break都可以跳出结束,continue,进入下一个循环。
system verilog调用C语言如何对DUT的信号进行采样和驱动?
使用Device Drive对DUT进行驱动
使用Monitor对DUT进行采样
怎么同步信号
关于Driver在verilog里面用task进行编写做一些行为级的建模,在SV用面向对象编程
同步驱动:
(1)要使用非阻塞赋值
(2)不能驱动异步信号
(3)不能驱动输入信号
同步信号:
2、并发性
线性执行并行的任务
关键字是fork–join
int a,b,c;
fork
statement0;
begin
statement1;
statement2;
end
join | join_any | join_none
statement3;
A;
fork
begin
recv();
end
begin
send();
end
join
这是两个线程
B:
fork
recv();
send();
join
两个线程
C:
fork
begin
recv();
send();
end
join
一个线程,顺序执行recv()和send()
D:
fork
begin
begin
recv();
send();
end
check();
end
join
一个主线程,两个子线程,其中一个子线程里面还有顺序执行。
fork—join是指其中里面语句执行完了才能执行外面的
fork–join_any是指只有里面有一个语句执行完了就会执行外面的语句
fork—join_none里面和外面的语句同时执行
3、封装OOP(Object Oriented Programming)面向对象编程
OOP就是复用
class driver;
string name;
bit [3:0] sa,da;
bit [7:0] payload [];
task send();
send_addrs();
send_pad();
send_payload();
endtask
task send_addrs();
...
endtask
task send_pad();
...
endtask
task send_payload();
...
endtask
endclass
class node;
static int count=0;
string str;
node next;
...
extern task ping();
endclass
task node::ping();
...
endtask