《SystemVerilog验证-测试平台编写指南》学习 - 第2章 数据类型
Posted yllinux
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《SystemVerilog验证-测试平台编写指南》学习 - 第2章 数据类型相关的知识,希望对你有一定的参考价值。
《SystemVerilog验证-测试平台编写指南》学习 - 第2章 数据类型
??SystemVerilog引进了一些新的数据类型,它们具有如下优点:
(1)双状态数据类型:更好的性能,更低的内存消耗;
(2)队列、动态和关联数组:减少内存消耗,自带搜索和分类功能;
(3)类和结构:支持抽象数据结构;
(4)联合和合并结构:允许对同一数据有多种视图(view);
(5)字符串:支持内建的字符序列;
(6)枚举类型:方便代码编写,增加可读性;
2.1 内建数据类型
??logic类型不能有多个结构性的驱动,在双向总线建模的时候要使用线网类型。
??logic类型只能有一个驱动,否则编译报错,所以logic可以用来查找顶层多驱动的错误。
双状态数据类型
??最简单的双状态数据类型是bit,它是无符号的。另外4种带有符号的双状态数据类型是byte、shortint、int和longint,如下所示:
bit b ; // 双状态,单比特无符号
bit [31:0] b32 ; // 双状态,32比特无符号整数
int unsigned ui ; // 双状态,32比特无符号整数
int i ; // 双状态,32比特有符号整数
byte b8 ; // 双状态,8 比特有符号整数
shortint s ; // 双状态,16比特有符号整数
longint l ; // 双状态,64比特有符号整数
integer i4 ; // 四状态,32比特有符号整数
time t ; // 四状态,64比特无符号整数
real r ; // 双状态,双精度浮点数
记:integer和time是四状态数据类型,integer是32位有符号,time是64位无符号。
注:
??你可能会乐意用byte数据类型代替logic[7:0]的声明,以使得程序更加简洁。但是需要注意的是这些新的数据类型是带符号的,所以byte变量的最大值只有127(取值范围-128 ~ 127)。可以使用byte unsigned,但这其实比使用bit[7:0]还要麻烦。在进行随机化时,带符号变量可能会造成意想不到的结果。
??若把双状态变量连接到待测设计,务必小心,如果待测设计产生了X或者Z,这些值会被转换为双状态值,而测试代码可能永远也察觉不了。这些值被转换为了0还是1并不重要,重要的是要随时检查未知值的传播。使用 $isunknown 操作符,可以在表达式的任意位出现X或者Z时返回1,如下例所示:
if ($isunknown(iport) == 1)
$display("@%0t: 4-state value detected on iport %b", $time, iport);
2.2 定宽数组
2.2.1 声明
??SystemVerilog允许只给出数组宽度的便捷声明方式,和C语言类似。
??可以通过在变量名后面指定维度的方式来创建多维数组。紧凑型声明方式是SystemVerilog特有的。
int lo_hi [0:15] ; // 16个整数[0]...[15]
int c_style [16] ; // 便捷声明,16个整数[0]...[15]
int array2 [0:7][0:3] ; // 完整的声明
int array3 [8][4] ; // 紧凑的声明
array2[7][3] = 1 ; // 设置最后一个元素为1
??若代码中试图从一个越界的地址中读取数据,那么SystemVerilog将返回数组元素的缺省值。比如,四状态logic返回X,双状态int或bit则返回0。这适用于所有数组类型,包括定宽数组、动态数组、关联数组和队列,也同时适用于地址中包含有X和Z的情况。线网在没有驱动时输出是Z。
??对于非压缩数组(非合并数组),很多SystemVerilog仿真器存放数组元素时使用32bit的字符边界,所以byte、shortint和int都是存放在相同长度的一个字中,而longint则存放到两个字中。例如:
bit [7:0] b_unpack [3] ; // 定义3个8位的非压缩数组
注:非压缩数组(非合并数组) 占用更多的内存空间。
2.2.2 常量数组
??使用:一个单引号加大括号来初始化数组。
??可以部分赋值;可以重复次数赋值;可以为那些没有显式赋值的元素指定一个缺省值。如下所示:
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
descend = ‘{9, 8, default:1} ; // {9, 8, 1, 1, 1}
2.2.3 基本的数组操作 -- for和foreach
??操作数组最常见的方式是使用 for 或者 foreach 循环。
??$size函数返回数组的宽度。
??在 foreach 循环中,只需要指定数组名并在后面的方括号中给出索引变量,SystemVerilog便会自动遍历数组中的元素,索引变量将自动声明,并只在循环内有效。
// 在数组操作中使用 for 和 foreach 循环
initial begin
bit [31:0] src [5] ; // 声明5个32位整数
bit [31:0] dst [5] ; // 声明5个32位整数
//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的值是srcd的2倍
end
// 初始化并遍历多维数组
int md[2][3] = ‘{‘{0, 1, 2}, ‘{3, 4, 5}} ; // 定义常量数组
initial begin
$display ("Initial Value:") ;
foreach (md[i, j]) // 正确语法格式
$display ("md[%0d][%0d]=%0d", i, j, md[i][j]) ;
$display ("New Value:") ;
// 对最后3个元素重复赋值5
md = ‘{‘{9, 8, 7}, ‘{3{32‘d5}}} ;
foreach (md[i, j]) // 正确语法格式
$display ("md[%0d][%0d]=%0d", i, j, md[i][j]) ;
end
??打印结果:
Initial Value:
md[0][0]=0
md[0][1]=1
md[0][2]=2
md[1][0]=3
md[1][1]=4
md[1][2]=5
New Value:
md[0][0]=9
md[0][1]=8
md[0][2]=7
md[1][0]=5
md[1][1]=5
md[1][2]=5
注意:foreach 的使用。
??如果不需要遍历数组中的所有维度,可以在 foreach 循环里忽略掉它们。看下面的例子,把一个二维数组打印成一个方形的阵列。它在外层循环遍历一个维度,然后再内层循环遍历第二个维度。
// 打印一个多维数组
initial begin
byte twoD [4][6] ; //
foreach (twoD[i, j])
twoD [i][j] = i * 10 + j ; //赋初值
foreach (twoD[i]) begin
$write ("%2d: ", i) ;
foreach (twoD[, j])
$write ("%3d", twoD[i][j]) ;
$display ;
end
end
??打印结果如下:
0: 0 1 2 3 4 5
1: 10 11 12 13 14 15
2: 20 21 22 23 24 25
3: 30 31 32 33 34 35
??补充:foreach 循环会遍历原始声明中的数组范围。如,
数组 f[5]等同于f[0:4],而 foreach (f[i]) 等同于 for (int i = 0; i <= 4; i++)。
数组 rev[6:2]来说,foreach (rev[i]) 等同于 for (int i=6; i >= 2; i--)。
2.2.4 基本的数组操作 -- 复制和比较
!-->!-->以上是关于《SystemVerilog验证-测试平台编写指南》学习 - 第2章 数据类型的主要内容,如果未能解决你的问题,请参考以下文章
SystemVerilog搭建测试平台---第一章:验证导论