1. 内建数据类型
1.1 逻辑(logic)类型
逻辑类型相当于verilog中reg变量的改进版,是的变量可以被连续赋值、门单元和模块所驱动;任何使用线网的地方都可以使用logic,唯一要注意的是logic不能进行多驱。
logic q,q_l,d,clk,rst_l;
1.2 双状态数据类型
双状态数据类型只有0,1两种取值,没有x和z态,这种类型有助于减少仿真时的内存占用。
bit b; //双状态,单比特
bit [31:0] b32; //双状态,32比特无符号整数
int unsigned ui; //双状态,32比特无符号整数
int i; //双状态,32比特有符号整数
byte b8; //双状态,8比特有符号整数
shortint s; //双状态,16比特有符号整数
longint l; //双状态,64比特有符号整数
interger i4; //四状态,32比特有符号整数
time t; //四状态,64比特无符号整数
2.定宽数组
2.1 定款数组的声明和初始化
SV中的定宽数组支持便捷声明方式,可以省略下边界,此时下边界默认为0。
//一维数组
int lo_hi[0:15]; //16个整数[0]...[15]
int c_style[15]; //16个整数[0]...[15]
//二维数组
int array2[0:7][0:3] //完整的声明,一个8行4列的数组
int array2[8][4]; //紧凑的声明
array2[7][3]=1; //设置最后一个元素
2.2 常量数组
在定义数组的同时,可以用一个单引号加大括号来初始化数组。
int ascend[4] = '{0,1,2,3}; //对四个元素进行初始化
int descend[5];
descend = '{4,3,2,1,0}; //为五个元素赋值
descend[0:2] = '{5,6,7}; //为部分元素赋值
descend = '{9,8,default:1}; //{9,8,1,1,1}
2.3 基本的数组操作
数组中最常用的是for和foreach循环。
//一维数组
initial begin
bit[31:0] src[5],dst[5];
for(int i=0;i<$size(src);i++)
src[i]=i;
foreach(dst[j])
dst[j]=src[j]*2; //dst的值是src的两倍
end
//多维数组
int md[2][3]; //一个3行4列的数组
initial begin
md = '{'{9,8,7},'{3{32'd5}}};
foreach(md[i][j])
$display("md[%0d][%0d]=%0d",i,j,md[i][j]);
end
数组可以在不使用循环的情况下进行比较和复制,注意此时操作的对象是整个数组;
initial begin
bit[31:0] src[5]='{0,1,2,3,4},
dst[5]='{5,4,3,2,1};
if(src==dst)
$display("src==dst");
else
$display("src!=dst");
end
2.4 合并数组
不同于非合并数组,合并数组的存放方式是连续的比特集合,中间没有任何闲置的空间。比如非合并数组的4个byte只会占用完整的1个字的内存,而非4个字进行高位补0。
声明合并数组时,合并的位和数组大小作为数据类型的一部分必须在变量名前面指定。 数组大小定义的格式必须是[msb:lsb],而不是[size]。
bit [3:0][7:0] bytes; //4个字节组装成32比特
bytes = 32'hCafe_Dada;
$displayh(bytes,, //显示所有的32比特
bytes[3],, //最高字节“CA”
bytes[3][7]); //最高比特位“1”
3.动态数组
SystemVerilog 提供了动态数组类型,可以在仿真时分配空间或调整宽度,这样就在仿真中就可以使用最小的存储量。
数组最开始是空的,所以必须调用new[]操作符来分配空间,同时在方括号中传递数组宽度。
int dyn[],d2[]; //声明动态数组
initial begin
dyn=new[5]; //分配5个元素
foreach(dyn[j]) dyn[j]=j; //对元素进行初始化
d2=dyn; //复制一个动态数组
d2=5; //修改复制值
dyn=new[20](dyn); //分配20个整数值并进行复制
dyn=new[100]; //分配100个新的整数值,旧值不复存在
dyn.delete(); //删除所有元素
end
4.队列
队列可以在任何地方增加或者删除元素,且性能损失比动态数组小的多。动态数组需要分配新的数组并复制所有元素的值。而且队列可以通过索引去实现任意元素的访问,不需要像链表一样去遍历目标元素之前的所有元素。
队列的声明是使用带美元符号的下标:[$]。队列元素编号从0到$。
int j=1,
q2[$]={3,4}, //对列的常量不需要'
q[$]={0,2,5}; //{0,2,5}
initial begin
q.insert(1,j); //{0,1,2,5} 在2之前插入1
q.insert(3,q2); //{0,1,2,3,4,5} 在q中插入一个队列
q.delete(1); //{0,2,3,4,5} 删除第一个元素
//下面操作执行很快
q.push_front(6); //{6,0,2,3,4,5} 在队列前面插入6
j=q.pop_back; //{6,0,2,3,4} j=5
q.push_back(8); //{6,0,2,3,4,8} 在队列末尾插入8
j=q.pop_front; //{0,2,3,4,8} j=6
q.delete(); //{} 删除整个队列
end
5.关联数组
用于超大规模范围的数组,用来保存稀疏矩阵的元素,只为实际写入的元素分配空间。仿真器采用树或者哈希表的形式来存放关联数组。
关联数组采用在方括号中放置数据类型的形式来进行声明。
initial begin
bit [63:0] assoc[bit[63:0]],idx=1;
//对稀疏分布的元素进行初始化
repeat(64) begin
assoc[idx] = idx;
idx = idx <<1;
end
//使用foreach遍历数组
foreach (asssoc[i])
$display("assoc[%h]=%h",i,assoc[i]);
//使用函数遍历数组
if(assoc.first(idx))
begin //得到第一个索引
do
$display("assoc[%h]",idx,assoc[idx]);
while(assoc.next(idx)); //得到下一个索引
end
//找到并删除一个元素
assoc.first(idx);
assoc.delete(idx);
$display("The array now has %0d elements",assoc.num);
end
6.链表
SystemVerilog虽然提供了链表,但应该避免使用它,队列的数据类型更加高效易用。
7.数组的方法
7.1 数组缩减方法
基本的数组缩减方法是把数组缩减成一个值。常见的数组缩减方法有sum(和),product(积),or(或)和xor(异或)。
bit on[10]; //单比特数组
int total;
initial begin
foreach(on[i])
on[i]=i; //on[i]的值为0或1
//打印单比特和
$display("on.sum=%0d",on.sum); //on.sum=1
//打印32比特和
$display("on.sum=%0d",on.sum+32'd0); //on.sum=1
//由于total是32比特变量,所以数组和也是32比特
total=on.sum; //total=5
//使用带32比特有符号的with表达式
$display("int sum=%0d",on.sum with(int'(item)));
end
7.2 数字定位方法
数组定位方法:min,max,unique,find。这些函数的返回值是一个队列而非标量。
在条件语句with中,item被称为重复参数,它代表数组中一个单独的元素。
int f[6] = '{1,6,2,6,8,6};
int d[] = '{2,4,6,8,10};
int q[$] = {1,3,5,7},tq[$];
tq = q.min; //{1}
tq = d.max; //{10}
tq = f.unique; //{1,6,2,8}
tq = d.find with(item > 2); //{4,6,8,10}
tq = d.find_index with(item>3) //{1,2,3,4}
tq = d.find_first with(item>99) //{}
tq = d.find_first_index(item==4) //{1}
tq = d.find_last with(item==10) //{10}
tq = d.find_last_index with(item==10) //{4}
7.3 数组的排序
数组排序方法:reverse(翻转)、sort(递增)、rsort(递减)和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}
8.strcut类型
SystemVerilog支持struct结构体,用于把数据组织到一起,创建新类型。
typedef struct {bit[7:0] r,g,b;} pixel_s;
pixel_s my_pixel;
9.枚举类型、
枚举类型可以自动为列表中的每个名称分配不同的数值。枚举值缺省为从0开始的整数。
typedef enum{INIT,DECODE,IDLE} fsmstate_e;
fsmstate_e pstate,nstate;
initial begin
case(pstate)
IDLE:nstate=INIT;
INIT:nstate=DECODE;
default:nstate=IDLE;
endcase
$display("Next state is %s",nstate.name()); //显示状态的符号名
end
10.常量
SystemVerilog支持const修饰符,允许变量声明时对其进行初始化,但不能在过程代码中修改其值。
initial begin
const byte colon=":";
...
end
11.字符串
SystemVerilog中的string变量可以用来保存长度可变的字符串。单个字符是byte类型。
string s;
initial begin
s="IEEE ";
$display(s.getc(0)); //显示:73('I')
$display(s.tolower()); //显示:ieee
s.putc(s.len()-1,"-"); //将空格变为'-'
s={s,"P1800"}; //"IEEE-P1800"
$display(s.substr(2,5)); //显示:EE-P
end