我的 System Verilog 学习记录(4)



引言

本文简单介绍 System Verilog 语言的 数据类型。

前文链接:

我的 System Verilog 学习记录(1)

我的 System Verilog 学习记录(2)

我的 System Verilog 学习记录(3)



数据类型简介

System Verilog 是 Verilog 的一个扩展,也可以用作HDL硬件描述语言。Verilog 具有reg 、wire等数据类型描述硬件行为。由于硬件验证越来越复杂,需求度越来越高,Verilog的数据类型已经不足以开发有效的testbench和testcase。因此 System Verilog 通过增加类似C语言的数据类型将Verilog扩展以实现更好的封装性和紧凑性。

下表给出了主要的数据类型:

 System Verilog 的注释和Verilog相同。

System Verilog 同样支持4态:

怎么写定点数和指数 ?

示例:

 仿真log:

System Verilog 的字符串是啥 ?

什么是结构体 ?

结构表示存储在一起并通过结构变量引用的数据类型的集合。

示例:

什么是固定大小的数组 ?

数组是在连续位置中存储不同值的变量。

示例:

 仿真log:

viod 数据类型

Void 数据类型表示不存在的数据,可以指定为函数和任务的返回类型,以指示没有返回值。

示例:

real 转 int

实数将通过将实数舍入到最近的整数而不是截断来转换为整数。如果小数部分正好为0.5,则将从零舍入。可以使用强制转换或使用系统任务指定显式转换。直接将实数值分配给整数类型也是舍入而不是截断。


logic 和 bit

4状态数据类型

4状态指的:0、1、X、Z,这和 Verilog 一致。reg类型数据只能在程序块(如 always 、initial)中驱动,而wire数据类型只能在 assign 语句中驱动。System Verilog引入了一个新的4状态数据类型logic,其既可以在程序块内驱动也在一在连续赋值 assign 语句中驱动但是当一个信号被多个器件驱动时,需要定义为线网类型,如wire,这样System Verilog 可以确定最终值

logic

示例:

仿真log:

2状态数据类型

在典型的验证测试平台中,有许多情况下我们并不真正需要所有四个值(0,1,x,z),例如,当使用指定包长度的报头对网络包进行建模时。长度通常是一个数字,但不是X和Z。SystemVerilog添加了许多新的两状态数据类型,这些数据类型只能存储,值为0或1。这将有助于更快的仿真,占用更少的内存,并且在某些设计风格中是首选的。

当4状态值转换为2状态值时,任何未知或高阻抗位都应转换为零。

最重要的两态数据类型是bit,它是testbench中最常用的。bit类型的变量可以是0或1,表示单个比特。应该提供从MSB到LSB的范围,使其表示和存储多个比特。

bit

示例:

仿真log:


integer 和 byte

除了Verilog支持的所有数据类型外,SystemVerilog还具有许多其他2状态数据类型。现代测试平台中最常用的数据类型有 bit , int , logic , byte。

integer

System Verilog 有3种新的有符号数据类型存放整数,每种的 size 不一样,最小的是 shortint ,范围:-32768~32767;最大的是 longint ,可以用通过关键字 signed 或者 unsigned 定义数据的符号性。当然也可以通过强制类型转换改变数据的符号性。

有符号(signed)

默认情况下,integer 变量是有符号数。

示例:

系统任务:$bits 返回变量的位宽。

仿真log:

无符号(unsigned)

示例:

 仿真log:

byte

字节是长度为8位的整数的更短版本。默认情况下,字节是带符号变量,并且具有与上一节中描述的整数相同的属性。

示例:

 仿真log:


字符串

System Verilog 中的字符串是啥 ?

字符串数据类型是字符的有序集合。字符串变量的长度可以具有动态长度且在仿真过程中可变化。字符串变量表示字符串的方式与字符串文字不同。使用字符串变量时不会发生截断。

语法

string variable_name [= initial_value] ;

variable_name 是有效的标识符,可选的 initial_value 可以是字符串文字、空字符串的值 " " 或字符串数据类型表达式。如果在声明时未指定初始值,则变量默认为” “空字符串文字。

举个栗子

 仿真 log :

 Verilog 中如何表示字符串 ?

单个ASCll字符需要8位(1字节),要存储字符串,我们需要的字节数与字符串中的字符数一样多。

 字符串操作符

示例:

仿真 log:

基本字符串方法

System Verilog 还包括许多使用内置方法表示法的特殊方法来处理字符串。

示例:

仿真 log:

字符串转换方法


枚举类型

枚举类型定义了一组命名值。在下面的示例中,light_*是一个枚举变量,可以存储三个可能的值(0,1,2)之一。默认情况下,枚举列表中的第一个名称获得值0,后面的名称获得像1和2这样的增量值。

用户可以为任何枚举的名称分配任何整数值。如果任何名称没有赋值,则它会自动采用先前名称的递增后的值。

 请注意,枚举名不能以数字开头

错误示例:

如何定义一个新的枚举类型 ?

可以创建自定义数据类型,以便可以使用相同的数据类型声明其他变量。

示例:

仿真 log:

为啥需要枚举啊 ?

为了代码的低复杂度和易读性。

如下的代码没有枚举:

增加枚举更加易读:

 枚举类型范围

 示例:

 仿真 log:

枚举类型方法

示例:

类型检查

枚举类型是强类型的,因此,除非使用显式强制转换,否则不能为枚举类型的变量赋值位于枚举集之外的整数值。

示例:

 Questa Sim 运行结果:

 主要是赋值的类型不匹配。应该用强制类型转换。

 更改强转后,Questa Sim 运行结果:


数组

SV 通过如下的几种数组,给复杂数据结构的建立提供了很大的灵活性。

  • 静态数组
  • 动态数组
  • 关联数组
  • 队列

静态数组

静态数组是指其大小在编译前已知的数组。在下面的示例中,声明了一个8位宽的静态数组,为其赋值并迭代以打印其值。

 静态数组进一步分为压缩数组和未压缩数组。

未压缩数组可以是固定尺寸数组、动态数组、关联数组或者队列。

动态数组

动态数组是指其大小在编译期间未知,但在运行时根据需要进行定义和扩展的数组。动态数组很容易通过其空方括号识别。

关联数组

关联数组是用某个 键 (Key)存储内容的数组。这很容易通过其方括号中存在的数据类型来识别。该键表示在方括号中。

队列

队列是一种数据类型,可以将数据推入队列或从数组中弹出。它很容易通过方括号内的符号 $ 识别。


压缩数组

压缩数组在变量名之前声明维度。

压缩数组保证表示为一组连续的位。它们只能由单个位数据类型(如 bit、logic 和其他递归压缩数组)组成。

一维压缩数组

亦称为向量。

仿真 log:

多维压缩数组

多维压缩数组仍然是一组连续的位,但也被分割成更小的组。

示例1:

下面显示的代码声明了一个占用32位或4字节的2D压缩数组,并遍历段并打印其值。

 仿真 log:

示例2:

三维压缩数组:

 仿真 log:


非压缩数组

非压缩数组在变量名之后声明维度。

非压缩数组可以是固定尺寸数组、动态数组、关联数组或者队列。

一维非压缩数组

 仿真 log:

多维非压缩数组

 仿真 log:

压缩数组+非压缩数组

 仿真 log:

在多维声明中,在名称之前声明的维度比在名称之后声明的维度变化更快。


动态数组

动态数组是一个未封装的数组,其大小可以在运行时设置或更改,因此与静态数组大不相同,静态数组的大小是在数组声明期间预先确定的。动态数组的默认大小为零,直到由new()构造函数设置。

语法

动态数组通过空的方括号声明。

new()函数用于为数组分配大小,并在需要时初始化其元素。

动态数组示例

动态数组方法

示例:

如何给动态数组添加新元素 ?

很多时候,我们可能需要在不丢失原有内容的情况下向现有动态数组中添加新元素。由于new()运算符用于为数组分配特定大小,因此我们还必须在创建后将旧数组内容复制到新数组中。

拷贝动态数组的示例:


关联数组

当集合的大小未知或数据空间稀疏时,关联数组是更好的选择。在使用关联数组之前,不会分配任何存储空间,索引表达式不限于整数表达式,但可以是任何类型。
关联数组实现其声明类型的元素的查找表。用作索引的数据类型用作查找键并强制排序。

语法

初始化栗子

 关联数组方法

示例:

仿真 log:

动态数组的关联数组

关联数组每个索引内的动态数组


数组操作方法

SystemVerilog中有许多内置方法可帮助进行数组搜索和排序。

数组操作方法只需迭代数组元素,每个元素用于计算With子句指定的表达式。迭代器参数指定可在With表达式中使用的局部变量,以引用迭代中的当前元素。如果未提供参数,则Item是默认使用的名称。

指定不带 with 子句的迭代器参数是非法的。

数组定位方法

对于这些方法中的某些方法,with 子句和表达式是必需的,而对于其他方法,则是可选的。

必选 ‘with’ 子句

这些方法用于根据给定的表达式从现有数组中筛选出某些元素。所有满足给定表达式的元素都被放入一个数组中并返回。因此,with 子句对于以下方法是必需的。

示例:

仿真 log:

可选 ‘with’ 子句

 示例:

数组排序方法

示例:

在类中使用数组排序

 仿真log:

数组归约方法

 示例:


队列

SV中的队列符合先入先出(FIFO)机制,存储控制可变,存储元素类型需相同。

它类似于自动增长和缩小的一维非压缩数组。它们还可以通过索引、连接和切片操作符进行操作。队列可以作为 ref 或非 ref 参数传递给任务/函数。

语法和应用

示例

啥是队列切片表达式 ?

切片表达式选择现有变量的子集。可以使用切片表达式选择队列元素,如下例所示。

一些仿真器会提供不同的结果,因此建议使用队列方法。

队列方法

除了数组运算符之外,队列还提供了几个内置方法。 

 示例:

如何创建类队列 ?

如何创建动态数组队列 ?

 示例:


结构体

一个结构可以包含不同数据类型的元素,这些元素可以作为一个整体引用,也可以通过它们的名称单独引用。这与元素属于相同数据类型的数组有很大不同。

语法

非压缩结构体

默认情况下,结构是非压缩的,可以使用 struct 关键字定义结构,并且可以在大括号中提供成员声明列表,后面跟着结构的名称。

示例:

定义结构体类型需要啥 ?

在上面的示例中只创建了一个变量,但如果需要创建具有相同组成的多个结构变量,最好是通过typedef 创建一个用户定义的结构数据类型。然后,结果将成为一个数据类型,然后可以用于创建该类型的变量。

压缩结构体

压缩结构体是一种将向量细分为字段的机制,这些字段可以作为成员访问,并在内存中打包在一起,没有间隙。结构中的第一个成员是最重要的,随后的成员按重要性递减的顺序排列。
结构声明使用 packed 关键字,默认是无符号的。

示例:


typedef

在复杂的测试台中,一些变量声明可能具有更长的数据类型规范,或者需要在测试台中的多个位置使用。
在这种情况下,我们可以使用 typedef 来为现有数据类型提供用户定义的名称。然后可以在整个代码中使用新的数据类型,因此避免在需要时在多个地方进行编辑。

语法

示例


  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在路上-正出发

哈哈,多少是个心意

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值