1. SV内建数据类型
- logic 逻辑值分别为 0/1/x/z,默认x无符号数
- bit 2值逻辑,分别为0/1,bit类型为无符号数
- byte shortint int longint
- 数据类型都为双状态,2值逻辑,分别为0/1
- 位宽分别为 8/16/32/64
- 都是有符号数
2. SV定宽数组
一维数组: int array[16]
二维数组: int array[8][4] 8行4列
int ascend[4] = ‘{0,1,2,3}; // 对4个元素进行初始化
int descend[5];
descend = ‘{4,3,2,1,0}; // 为5个元素赋值
descend[0:2] = ‘{5,6,7}; // 为前3个元素赋值
ascend = ‘{4{8}}; // 4个值全部为8 {8,8,8,8}
descend = ‘{9, 8, default:-1}; // {9,8, -1, -1, -1}
//常用for循环遍历数组
initial begin
bit [31:0] src[5],dst[5];
for (int i=0; i<$size(src); i++) //i为局部变量,$size函数返回数组的宽度
src[i] = i;
end
initial begin
bit [31:0] src[5],dst[5];
foreach (dst[j])
dst[j] = src[j]* 2; //二维数组亦为SV常用数组
end //使用foreach方便快捷的遍历数组
3. SV动态数组与关联数组
动态数组,可以在仿真时分配空间或者调整宽度
声明使用空的[],在使用数组之前一定要调用new[]操作符来分配空间
int dyn[], d2[];// Declare dynamic arrays
initial begin
dyn = new[5]; //A: Allocate 5 elements
foreach (dyn[j]) dyn[j]= j; // B: Initialize the elements
d2 = dyn; // C: Copy a dynamicarray
d2[0] = 5; //D: Modify the copy
$display(dyn[0],d2[0]); // E: See both values(0 & 5)
dyn = new[20](dyn); // F: Allocate 20 ints& copy
dyn = new[100]; //G: Allocate 100 new ints
// Old values are lost
dyn.delete(); // H: Delete allelements
end
动态数组提供了一些内建的方法:delete和 size
int test[];
test=new[4]; //用new来创建数组
num=test.size(); //用size获取数组大小
test.delete(); //用delete删除数组
关联数组类型,用来保存稀疏型的数据,有利于使用零散的存储空间
- 关联数组的索引
-
通配符索引:任意数据类型进行索引:int array_name [*];
-
字符串索引:int array_name[string];
-
类索引:int array_name [some_Class];
-
integer(或int)索引:int array_name[integer];
-
有符号的压缩数组索引:typedef bit signed [4:1] Nibble; int array_name[Nibble];
-
无符号的压缩数组索引:typedef bit [4:1] Nibble; int array_name [Nibble];
-
其它用户定义类型索引:typedef struct { real R; int I[*]; } Unpkt; int array_name [Unpkt];
num() //返回数组长度
delete() //删除指定元素或者所有元素
exists() //检查是否元素存在,存在返回1,否则返回0
first() //将指定的索引变量赋值为数组第一个索引的值
last() //将指定的索引变量赋值为数组最后一个索引的值
next() //索引变量被赋值为下一个条目的索引
prev() //索引变量被赋值为上一个条目的索引
简单的for循环不能遍历关联数组,需要使用foreach遍历数组,还可以使用内建的first()和next()函数。
读取不存在的关联数组元素,4值逻辑返回x,2值逻辑返回0。
4. SV结构体与枚举
//struct_name.a可以引用结构体内部的a变量
struct {
int a;
int b;
bit c;
} struct_name
//定义结构体的同时给结构体赋值
typedef struct {
int addr = 1 + constant;
int crc;
byte data [4] = '{4{1}};
} packet1;
如果没有特别说明,枚举数据默认的存储类型为int型,且数值从0开始递增
enum{INIT, DECODE, IDLE} state; //INIT:0 DECODE:1 IDLE:2
enum{A=2, B=5, C, D=30, E, F} dic; //A=2 B=5 C=6 D=30 E=31 F=32
- 枚举类型方法
first() //returns the first member of theenumeration.
last() //returns the last member of theenumeration.
next() //returns the next element of theenumeration.
next(N) //returns the Nth next element.
prev() //returns the previous element ofthe enumeration.
prev(N) //returns the Nth previous element.
5. SV队列及数组方法
队列声明格式 int data [$],
queue_name.size //返回queue的大小
queue_name.insert(index,item) //在某个索引处插入某元素
queue_name.delete(index) //刪掉某元素或整个queue
queue_name.pop_front() //去除第一个元素
queue_name.pop_back() //去除最后一个元素
queue_name.push_front() //插入元素到queue(0)
queue_name.push_back() //插入元素到queue($)
可以在队列的任意地方实现元素的增删改查,注意不要对队列使用构造函数new[]。
q = {e, q}; // 在队列的头部插入'e'
q = q[1:$]; // 删除第一个(最左边)元素
q = q[0:$-1]; // 删除最后一个(最右边)元素
q = q[1:$-1]; // 删除第一个和最后一个元素
q = {}; // 清除队列(删除所有的元素)
q = {q[0:pos-1], e, q[pos:$]}; // 在位置'pos'处插入'e'
- SV数组方法
- 1.数组缩减方法:sum(求和)、product(求积)、and(与)、or(或)、xor(异或)
int count, total, d[] = ‘{9,1,8,3,4,4}; count = d.sum with (item > 7); // 2: {9, 8} total = d.sum with ((item > 7) * item); // 17= 9+8 byte b[] = ‘{ 1, 2, 3, 4}; int y; y = b.sum ; // y becomes 10 => 1 + 2 +3 + 4 y = b.product ; // y becomes 24 => 1 * 2 *3 * 4 y = b.xor with ( item + 4 ); // y becomes12 => 5 ^ 6 ^ 7 ^ 8
- 2.数组定位方法
—min()
—max()
—unique()
—find() //returns all the elements satisfying the givenexpression.
—find_index() //returns the index of all the elements satisfying the given expression.
—find_first() //returns the first element satisfying the givenexpression.
—find_first_index() //returns the index of the first element satisfying thegiven expression.
—find_last() //returns the last element satisfying the givenexpression.
—find_last_index() - 3.数组排序方法:sort、rsort、reverse、shuffle
int d[] = ‘{9,1,8,3,4,4}; d.reverse();// ‘{4,4,3,8,1,9} d.sort();// ‘{1,3,4,4,8,9} d.rsort();// ‘{9,8,4,4,3,1} d.shuffle();// ‘{9,4,3,8,1,4}
6. SV过程语句
initial语句在仿真一开始就立刻开始执行(0时刻),每个initial语句只执行一次。
多个initial块并行执行,每个块的执行是独立的。
initial //语句块内含2条或以上语句需要使用begin…end或
begin
statement1;//可以是过程赋值语句/分支语句
statement2; //循环语句,等待语句,顺序执行语句/并行执行语句
….. ;
statementN;
end
module example_initial;
reg clk;
reg a,b;
initial begin
clk=1’b0;
#2 a=1;
#3 b=1;
#5 a=1;
b=1
end
endmodule
SV对Verilog 的always语句做了扩展,除了always外还有:
-
always_comb //组合逻辑建模
-
always_latch //为latch建模
-
always_ff //为时序逻辑建模
final语句
-
当一个显式或隐式的$finish调用引起仿真结束的时候会执行final块。
-
final块只能在一次仿真中触发一次。
final
begin
$display("Number of cyclesexecuted %d",$time/period);
$display("Final PC = %h",PC);
end
initial begin
…
$finish();
end
7. SV控制流
unique if指示在一系列if...else...if条件中不应该有任何交迭,也就是说,这些条件是互斥的.如果有多于一个条件为“真”,则会报错。
priority if指示一系列if...else...if条件应该按列出的顺序计算。如果多个条件同时满足,那么选择第一个满足条件的分支,即具有优先级逻辑。
priority case仅仅作用于第一个匹配。
unique case应该检查case条目的交迭。如果多于一个case条目匹配于case表达式,那么unique case应该发布一条警告信息。
Verilog提供了for、while、repeat以及forever循环。
SystemVerilog增强了Verilog的for循环,加入了一个do...while循环和一个foreach循环
initial
begin:example
integer array[10], sum, j;
// Declare i in for statement
for (int i=0; i<10; i++) // Increment i
array[i] = i;
// Add up values in the array
sum = array[9];
j=8;
do // do...whileloop
sum += array[j]; // Accumulate
while(j--); // Test ifj=0
$display("Sum=%4d", sum); // %4d - specify width
end : example
string words[2] ={"hello", "world"};
int prod[1:8][1:3];
foreach (words[j])
$display(j, words[j]); // 打印每一个索引和值
foreach (prod[k,m])
prod[k][m] = k * m; // 初始化
repeat(5) @(posedge clk)
break
像C语言一样跳出循环,结束循环体。
continue
像C语言一样跳转到循环的尾部,结束本次循环,继续下一次循环。
return expression
退出一个函数且具有返回值,expression必须具有正确的类型,否则会报错。
return
退出一个任务或void函数
disable语句用于终止正在运行的代码块。可以分为diable fork以及disable lable
8. SV块语句
- 顺序块:语句置于关键字begin和end之间,块中的语句以顺序方式执行。
命名块:可以为块语句定义一个标识名称,将块名加在begin或fork后面 - 并行块:关键字fork和join父进程会阻塞直到这个分支产生的所有进程结束
join_any父进程会阻塞直到这个分支产生的任意一个进程结束。
join_none父进程会继续与这个分支产生的所有进程并发执行。在父线程执行一条阻塞语句或者结束之前,产生的进程不会启动执行。
之间的是并行块语句,块中的语句并行执行。
在定义一个fork...join块的时候,将整个分支封装在一个begin...end块中会引起整个块作为单个进程执行,其中每条语句顺序地执行。
// wait fork; 指定waitfork会引起调用进程阻塞直到它的所有子进程结束
task do_test;
fork
exec1();
exec2();
join_any
fork
exec3();
exec4();
join_none
wait fork; // 阻塞直到exec1... exec4完成
disable fork; //中止调用进程的所有活跃的子进程。
endtask
9. SV task与function
SystemVerilog加入了在静态任务和函数中声明自动变量的功能。
在自动任务和函数中声明静态变量的功能。
无需一个begin...end块或fork...jion块就可以在一个任务或函数中使用多条语句的能力。
在到达任务或函数的结尾之前从任务或函数返回的能力。