当前位置:网站首页>【SystemVerilog 之数据类型】~ 数据类型、Logic 类型、数组

【SystemVerilog 之数据类型】~ 数据类型、Logic 类型、数组

2022-06-09 10:40:00 AI很不错呦

1. 数据类型

1.1 四值变量

四值变量:(0、1、x、z)四种状态

四值逻辑类型:integer、reg、logic、reg、net-type(如 wire、tri);

SV 并不太常用变量类型是 wire(assign 语句中)还是 reg(initial 和 always 语句中)。logic 用的比较多。可以被连续赋值语句驱动,可用在 assign、initial、always 语句中。

1.2 二值变量

二值变量:(0、1)两种状态

二值逻辑类型:byte(8位)、shortint(16位)、int(32位)、longint(64位)、bit。

1.3 有符号与无符号

有符号类型:byte、shortint、int、longint、integer。
无符号类型:bit、logic、reg、net-type(如 wire、tri)。

1.4 四值变量与二值变量的特性

四值变量的默认初始值为 x,二值变量的默认初始值为 0,在 initial 中可以直接使用~clk 变 成 1,但是如果是 logic,必须设置初值为 0、或者 1。将四值变量赋值给二值变量,x 和 z 状态会转变为 0。

1.5 转换方式

对于转换方式,可以分为隐式转换和显式转换。显式转换又可以分为静态转换和动态转换
静态转换:unsigned’(signed);注意单引号。
动态转换:$cast(tgt,src)

2. Logic 类型

在 SystemVerilog 中,可以在过去 verilog 中用 reg 型或是 wire 型的地方用 logic 型来代替。

实际上 logic 是对 reg 数据类型的改进,使得它除了作为一个变量之外,还可以被连续赋值、门单元和模块所驱动,显然,logic 是一个更合适的名字。抛去 inout 类型外,其余所有的变量都可以声明为 logic 类型,不用区分线网和变量 reg 之间的不同点。

值得注意的是,logic 不能有多个结构性的驱动,也就是说,logic 不允许使用多于一次的持续赋值语句和输出端口连接的给同一变量赋值。这是因为没有类似于线网的多重驱动变量的定论。因此,假如你通过这些方式给一个变量赋过值,你将不能再用过程赋值语句给变量赋值。

3. 数组

对于前面的一个变量名代表一个数据,如果我们有很多数据要表示就会很麻烦,这样就可以用一个数组来储存,且对数组进行操作可以快速处理多个数据,数组分为:定宽数组、动态数组、队列、关联数组、链表。

3.1 定宽数组

指定了数组宽度的数组

3.1.1 一维定宽数组的声明

int a[8];
int b[0:07];

在变量名后指定数组宽度可创建一维数组,由于数组序号从0开始计算,所以[0:7]的写法和直接写[8]在SV中都是表示创建一个一维的数组,且数组中元素个数为8即a[0]、a[1] … a[7]

3.1.2 多维定宽数组的声明

在这里插入图片描述

上图表示创建了二维数组,其大小为8行4列,二者写法等同,注意区分 数组宽度是[0:n] 并写在变量名后,数据位宽是[n:0]写在变量前

3.1.3 合并数组与非合并数组

从内存存放的角度考虑,其数据存放在计算机的内存时可以连续存放,也可以不连续存放,如(bit [7:0] a [4] )为数组宽度为4,数据位宽为8的数组,如下图:
在这里插入图片描述
构成了非合并数组(不连续存放)和非合并数组(连续存放),很多SV仿真器在存放数组元素时使用32比特(位)的字边界,所以byte、shortint、int都是存放在一个字中,可以看到上图有颜色的数据部分占了低8位,灰色代表剩下的高位没有数据存放而空着,显然非合并数组占用的内存更多。

3.1.3.1 非合并数组的声明

在这里插入图片描述

当索引(数组宽度定义)位于数组名后方时,定义的就是非合并数组,其数据在内存是不连续存放的。

3.1.3.2 合并数组的声明

bit [3:0][7:0] a;

把索引移到最前面时,定义的就是合并数组,其数据在内存是连续存放的,此时的[3:0]不能简写成[4],存放的数据从右到左为a[0]、a[1]、a[2]、a[3]。

3.1.3.3 合并数组和非合并数组可以混合使用

bit [3:0][7:0] a[3];

表示有3个合并元素的非合并数组,即一个含3个元素的非合并数组 a,a中的每个元素都形如合并数组,如下图:
在这里插入图片描述

3.1.3.4 合并数组与非合并数组的选择

由于非合并数组是不连续储存,如果要将这个数组内全部位数都赋值为一个值如 0 的时候就必须用{0,0,…}的形式,而合并数组可以直接写成(a = 0),具体数组操作在下面讲,其余直接引用绿皮书的说明:合并数组与非合并数组的选择——当需要和标量进行相互转换时,使用合并数组会非常方便;任何数组类型都可以合并;如果需要等待数组中的变化,则必须使用合并数组。当测试平台需要通过存储器数据的变化来唤醒时,你会想到使用@操作符,但是该操作符只能用于标量或合并数组.

3.1.4 数组的初始化

数组可以在定义时赋值(初始化),也可以在定义后赋值。

3.1.4.1 非合并数组的赋值

在这里插入图片描述

蓝色字代表注释的内容不参与仿真时不参与运算,注释用/* */和//表示,后面的赋值要写成 '{ , , } 的形式,注意大括号前有一个 ’ 的标点,如果全赋值成1的时候不能直接写成(a = 1),因为非合并数组内存存放是不连续的,此时打印 a 的值的话仿真结果报错,可以按(a[0]=1,a[1]=1 …)这种格式赋值,所以大括号内要用逗号隔开分别赋值,上图的输出结果为:
在这里插入图片描述
其余例子:
在这里插入图片描述

3.1.4.2 合并数组的赋值

在这里插入图片描述

对于合并数组,多了可以写成(a = 1)将数组a的3个元素一次性赋值成1的方式,上图将{0,1,2}赋值给了合并数组a,输出结果为:
在这里插入图片描述

对于{0,1,2}的赋值,结合图7,可以看出,{0,1,2}依次对应内存储存中从左到右的a[2]、a[1]、a[0],与非合并数组内存储存中从上到下的a[0]、a[1]、a[2]顺序相反,而此时 a 的值打印显示也是由3个8位数组成24位数。

3.1.5 基本的数组操作

3.1.5.1 for和foreeach

操作数组最常见的方式是使用for和foreach循环,见下例:
在这里插入图片描述

定义了元素个数为4(数组位宽为4)、每个元素为8位宽的一维定宽数组(非合并),对数组a采用for循环赋值,$size(a)为a的数组位宽,即 i 的值小于4就可以一直循环,每次循环令(a[i] = i),定义(int i = 0),这里 i 的类型要定义否则仿真报错,i 的初始值不定义则默认为0。接下来的foreach循环意思为遍历,只要指定了数组名和后面方括号中的索引值(即a[]),SV就会遍历数组中的元素,相当于省略了for循环()里的条件,是简便的写法。这里用foreach循环使得数组 b 的元素等于数组 a 对应元素值的两倍。

for和foreach循环内的循环变量可以是任意字母,如上面还用了k,n,只是习惯for循环内用 i ,foreach里用 j ,注意此时的 i 或 j 或其他字母是循环内自动声明的变量,不会影响到循环外的代码,如果自己在外面定义个 i 或 j 并赋初始值的话,在本次循环内也不起作用,以下是仿真结果:
在这里插入图片描述

注意:for和 if 等条件判断语句后面不加分号(;),因为分号代表这一行代码结束,加了会导致条件判断不生效。

二维数组的话用foreach遍历会简单许多,如下图:
在这里插入图片描述

注意:在foreach的()内写的是 [i,j] ,其中i,j表示两个维度的循环,而在下面的赋值和打印操作中则必须写成 a[i][j] 的形式,否则仿真报错。

3.1.5.2 数组的复制和比较

两个数组之间可以进行赋值和比较,如下例:
在这里插入图片描述

定义了两个数组并赋值,a 赋值{0,1,2,3},b赋值{0,0,0,0},用 if 语句判断数组 a 和 b 中每个元素是否相等,相等则返回1执行if下的语句,否则返回0执行else下的语句,注意大于一行命令的时候,if 和else后面都要用begin end包上(类似C语言的{}),第一个 if 语句肯定是不相等,之后把数组 a 的值赋给数组 b ,此时第二个 if 语句判断为相等,仿真结果如下:
在这里插入图片描述

下集预告

学习动态数组、队列、关联数组、结构体、枚举、字符串等相关的知识。

希望我可以坚持下去,不断学习!如果觉得有用,希望关注点赞评论,不迷路!!!

声明:仅供学习参考,侵删!!!

参考文献:
写的很好,大佬的笔记,供参考

原网站

版权声明
本文为[AI很不错呦]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_40549426/article/details/125192249