《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 基本的数组操作 -- 复制和比较

猜你喜欢

转载自www.cnblogs.com/yllinux/p/13200475.html