SystemVerilog中扩展了Verilog中的数据类型,增加双状态数据、动态数组、队列等。
1. 内建类型 1.1 logic类型 SV中将reg类型替换成logic关键字,logic既可以在块语句中被赋值,也可以在assign中被赋值,可以用wire的地方都可以用logic来替换,但logic不能有多个驱动,比如双向总线建模的时候需要用wire。
1.2 双状态数据类型 只有0 1两个状态,没有x z,有利于提高仿真器性能,减少内存使用。
bit b; bit [31 :0 ] b32 ;int unsigned ui ;int i ;byte b8; shortint s; longint l;integer i4; time t;real r;
如果将双状态的变量连接到DUT的输出,那么如果输出x或z,将被转换成0或1,而不能检测到x z。使用$isunknown操作符可以在表达式位x或z的时候返回1.
2. 定位宽的数组 2.1 定义和初始化 1 2 int lo_hi[0 :15 ]; int c_type[16 ];
初始化用单引号和花括号 组合。
1 2 3 int ascend[4 ] = '{0 ,1 ,2 ,3 }; ascend[0 :1 ] = '{1 ,1 }; ascend='{0 ,1 ,default :1 };
2.2 foreach遍历数组 1 2 3 4 5 initial begin int ascend[4 ] = '{0 ,1 ,2 ,3 }; foreach (ascend[i]) ascend[i]*=2 ;end
2.3 遍历多维数组 1 2 3 4 5 initial begin int arr[2 ][3 ] = '{'{0 ,1 ,2 },'{3 ,4 ,5 }}; foreach (arr[i,j]) $display ("%d\n" ,arr[i][j]); end
也可以分开遍历
1 2 3 4 5 6 7 8 initial begin int arr[2 ][3 ] = '{'{0 ,1 ,2 },'{3 ,4 ,5 }}; foreach (arr[i]) begin $display ("%d:\n" ,i); foreach (arr[,j]) $display ("%d\n" ,arr[i][j]); end end
2.4 赋值和比较 两个数组间可以直接赋值,比较
1 2 arr1 = arr2; arr1 == arr2;
2.5 合并数组 既可以当作单独的数据,也可以分成几个小份作为数组。
1 2 3 4 5 bit [3 :0 ][7 :0 ] bytes; bytes = 32'hCafe_Dada ; bytes; bytes[3 ]; bytes[3 ][0 ];
用途:
如果需要标量与数组的转换用合并数组。
如果需要等待信号变化,用合并数组,比如唤醒@操作符
1 2 3 4 bit [0 :3 ][7 :0 ] bytes;bit [7 :0 ] arr[4 ]; @bytes ; @arr;
3. 动态数组 定宽数组的宽读在编译的时候就确定了。如果想在仿真时生成事务,但事务的总量是随机的,那么就需要用一个很宽的数组,但实际上可能只需要很小的数组,造成存储空间浪费。SV中提供动态数组,数组在仿真时分配存储空间。用[ ].用new[]来分配空间,delete()删除元素。
1 2 3 4 5 6 7 initial begin int dyn[],dyn2[]; dyn = new [4 ]; foreach (dyn[i]) dyn[i] = i; dyn2=new [4 ](dyn); dyn.delete (); end
定宽数组可以给动态数组赋值,编译器自动调用new函数。
4. 队列 queue 可以在队列任何地方增加或者删除元素,在性能上的损耗比数组小。**$符号。**
还括号初始化,但不需要单引号。
最后一个索引是$.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 initial begin int j=0 ; q1[$] = {0 ,1 }; q2[$] = {2 ,3 ,4 }; q1.insert (1 ,10 ); q1.insert (1 ,q2); q1.delete (1 ); q1.push_front (1 ); j=q1.pop_front ; q1.push_back (1 ); j=q1.pop_back (); foreach (q1[m]) q1[m]; q1 = {q1[0 ],q1[1 :4 ]}; q1 = {q1[0 ],j,q1[1 :$]}; end
5. 关联数组 关联数组就是哈希,保存键值对。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 12 min_address123 max_addressinitial begin int switch[string ]; int min_add,max_add; int i,r,file; string s,idx; file = $fopen ("switch.txt" ,"r" ); while (!$feof (file)) begin r = $fscanf (file,"%d %s" ,i,s); switch[s] = i; end switch.exist ("max_address" ); switch.first (idx); switch.next (idx); switch.delete (idx);end
6. 数组的方法 6.1 $size 1 2 3 4 initial begin int arr[4 ] = '{0 ,1 ,2 ,3 }; $size (arr);end
6.2 sum\product\or\xor sum方法,返回元素宽度的值。
1 2 3 4 5 initial begin bit [0 :7 ] arr[4 ] = '{1 ,2 ,3 ,4 }; arr.sum ; 32 ‘b + arr.sum ; end
6.3 定位数组元素 max最大值、min最小值、unique返回不重复的元素。
这些方法可以用在定宽数组、动态数组、队列中。返回类型是队列。
1 2 3 4 5 int f[6 ] = '{0 ,1 ,2 ,2 ,4 ,1 };int q[$]; q = f.max ; q = f.min ; q = f.unique ;
with用来定位数组中的元素,与其他方法一起使用。
1 2 3 4 5 6 7 q = f.find with (item > 2 ); /找到大于2 的元素,也是返回队列 q = f.find_index with (item >2 ); q = f.find_first with (item >2 ); q = f.find_first_index with (item >2 ); q = f.find_last with (item >2 ); q = f.find_last_index with (item >2 ); sum = f.sum with (item >2 );
在条件语句with中item是重复参数,默认是item,也可以制定其他值
6.4 数组排序 reverse,sort(从小到大),rsort(从大到小)
7. 元素类型选择 动态数组:子程序中最好用动态数组,这样子程序可以对不同长度的数组进行处理,只需要程序参数匹配就行了。
关联数组:用在索引不规则的时候。比如由于随机值产生的分布索引
队列:当数组的元素数目变化很大的时候用队列,比如保存预期值的记分板中。
$size(array) 返回数组宽度
8. typedef定义类型 1 typedef unsigned int u32;
9. 创建自定义结构 9.1 struct 1 2 3 4 typedef struct { int a; string b;} my_struct; my_struct st = '{1 ,'dong'};
用单引号和花括号来初始化。
9.2 合并结构packed 合并结构以连续的bit集来存放数据,
1 typedef struct packed {bit [7 :0 ] a,b,c;} p_s;
合并struct和非合并struct的区别在于仿真的效率上。P42《绿皮书》
10. 枚举类型 10.1 定义 枚举类型可以为列表中的每个名称赋值。
1 2 3 4 5 6 7 8 9 10 typedef enum {INIT,DECODE,IDLE} fstate_e; fstate_e nstate,pstate;initial begin case (pstete) IDLE:nstate <= INIT; INIT:nstate <= DECODE; DECODE:nstate <= IDLE; endcase $display ("nstate name is %s" ,nstate.name ()); end
name()函数返回当前枚举值的符号名。
声明了枚举变量fstate_e之后,INIT,DECODE,IDLE这些名字可以直接拿过来用。它们的默认值是从0开始,递增,当然也可以自己设置.
注意:枚举类型被当作int来存在,如果定义变量的时候没有初始化,那么默认将枚举变量初始化为0,但如果在定义枚举变量的时候没有0,那么出错。如下面:
1 2 3 4 5 typedef enum {INIT=1 ,DECODE} state_e;initial begin state_e p=1 ; state_e pp;end
10.2 枚举子程序 1 2 3 4 5 6 first(); last() next()下一个,会绕回 next(N)下N个 prev()前一个 prev(N)前N个
11. 常量 const 12. 字符串 string 1 2 3 4 5 6 getc(index)tolower () tohigher() len() substr(index1,index2); $psprintf();
13. 类型转换 13.1 静态转换 1 2 3 4 initial begin int i; i = int '(10 .0 -0 .1 );end
13.2 动态 $cast 13.3 流操作符 “>>”是将bit从左到右排列,转换成一个数据。
“<<”是将bit从右到左排列,转换成一个数据。
1 2 3 4 5 6 7 8 9 10 11 12 initial begin int h; bit [0 :7 ] g[4 ],j[4 ] = '{8'ha ,8'hb ,8'hc '8'hd }; bit [0 :7 ] q; bit [0 :7 ] b1,b2,b3,b4; h = {>>{j}}; h = {<<{j}}; h = {<<byte {j}}; g = {<<byte {j}}; q = {<<4 {8'b0001_1000 }}; {>>byte {b1,b2,b3,b4}} = {>>byte {j}};end