systemverilog绿皮书随记(一)--数据类型

lite_ic_verifier 2024-09-11 10:33:01 阅读 72

2.1内建数据类型

Sv中的reg可以进行连续赋值

logic只能有一个驱动;若是信号本身有多个驱动,则需要被定义为wire线网类型;

二值逻辑和四值逻辑:

Logic是四值逻辑:1,0,X,Z;bit为二值逻辑;1,0

Sv引入四值逻辑是期望硬件世界和软件世界分离开。四值逻辑属于硬件设计,二值逻辑属于验证环境;

四值逻辑:integer,logic,reg,wire

二值逻辑:byte,shortint,int,longint,bit

无符号的四值逻辑中的一个位x,转换为无符号的二值逻辑会等于0

接口内的信号需要DUT连接,因此要用四值逻辑来确保有x和z状态,而非二值逻辑。接口中最好以使用 logic 做为信号的类型。因为logic可以直接赋值,而 wire 必须要被连续赋值语句可来驱动。

有符号类型:beyt,shortint,int,longint,integer

无符号类型:bit,logic,reg,wire

有符号数:负数以补码的形式储存;正数以原码形式储存;最高位为符号位,0为正数,1为负数;

不同类型的数据进行操作时,应该注意变量的:1.逻辑数值类型2.符号类型3.矢量位宽

2.2定宽数组

2.2.1定宽数组的声明和初始化

如果试图从一个越界的地址中读取数据,那么sv将返回数组元素类型的缺省值;对于一个元素为四状态类型的数组,返回的是X;而对于双状态数组,则返回0;

存放四值类型数据会比存放两值类型数据多占用一倍的空间

用一个单引号和大括号来初始化数组`{};

2.2.2常量数组

int descend[5];

descend = `{4,3,2,1,0}//`{9,8,3{1}}//`{6,5,default:0}

2.2.3for和foreach

$size函数返回数组的深度

for 和 foreach会按照数组中元素的索引值开始遍历。也就是说:

对于 f[0:4] 数组,遍历索引值从 0 ~ 4,采样foreach(f[i]),等同于for( int i = 0; i <= 4; i ++)

对于 f[6:2] 数组,遍历索引值从 6 ~ 2,foreach(f[i]),等同于for( int i = 6; i <= 2; i --)

int array2 [2] [3] = '{'{2,3,4},'{4,5,6}};

//遍历方式一://推荐!!!

foreach( array2[i,j] ) $display("数组中第[%0d] [%0d]= %0d;",i,j,array1[i][j]);

//遍历方式二:

foreach(array[i]) begin

  foreach(array[,j]) $display("数组中第[%0d] [%0d]= %0d;",i,j,array1[i][j]);

end

2.2.4复制和比较

对于组合型,数组会被视为一个向量,即便两边的操作数的维度不相同时,也可以做赋值

长的赋值给短的,会截断高位,保留跟短的相同长度的低位

短的赋值给长的,短的会占据低位,高位会被填充为0

对于非组合型,要求左右两侧操作数的维度和大小必须一致

非组合型无法直接赋值给组合型;同样组合型也无法直接赋值给非组合型

2.2.5合并数组

它可以作为一个整体来访问,也可以把他分解成更小的单元;它的存放方式是连续的集合,中间没有任何闲置的空间。

声明合并数组的时候,合并的位和数组大小作为数据类型的一部分必须在变量名前面指定。合并数组大小定义的格式必须是[msb,lsb],而不是[size]

2.3动态数组

动态数组在声明时使用空的下标[],数组在最开始时是空的,所以你必须调用new[]操作符来分配空间,同时在方括号中传递数组宽度;

int dyn[],d2[];

  dyn = new[5];

  d2=dyn;//复制一个动态数组

  dyn=new[20](dyn);//分配20个整数值并进行复制

  dyn=new[100];

  dyn.delete();//删除所有元素

当定宽数组复制给一个动态数组时,sv会调用构造函数new[]来分配空间并复制数值;

只要基本数据类型相同,定宽数组和动态数组之间就可以相互赋值;

动态数组赋值

在new[ ]中设置动态数组大小时,并不完全需要匹配所赋数组的大小。当初始化动态数组的大小较大时,赋值的常量数组会被截断以匹配;当它较小时,初始化的数组将使用默认值填充以获得指定的大小。如下:

int src[3] = '{2, 3, 4};

int dest1[];

int dest2[];

dest1 = new[2] (src); // dest1中的元素为: {2, 3} ,数组被截断

dest2 = new[4] (src); // dest2中的元素为: {2, 3, 4, 0} ,用默认值0 补齐

2.4队列

队列可以在任何一个地方增加或删除元素,且这类操作的性能上的损失比动态数组小的多;

对队列赋值只有大括号,没有单引号;队列是连续储存的

//对于内存连续储存的数组,赋值不需要使用单引号

//对于内存不连续的数组,赋值需要使用单引号

可以把定宽或动态数组的值复制给队列

2.5关联数组

用来保存稀疏矩阵的元素;仿真器可以采用树或哈希表的形式来存放关联数组,会有一定的开销;关联数组采用在方括号中放置数据类型的形式来进行声明;

还可以使用exists()来检查元素是否存在

2.6链表

书中没有展开介绍,作者建议尽量避免使用

2.7数组方法

min(),max()函数能够找出数组中的最小值和最大值;返回值是一个队列不是标量

unique()返回的是在数组中具有唯一值的队列,即删除掉重复的数值;

Shuffle()是乱序函数

2.8使用typedef创建新的类型

规范用户自定义类型都带后缀_t;

2.9自定义结构体

Struct是一个数据集合;如果想生成带约束的随机数据,那就应该使用类了;

默认的结构体是非组合型的,赋值是要把数值放到带单引号的大括号中;

规范用户自定义结构体都带后缀_s;

合并结构体:typedef struct packed {bit [7:0] r,g,b} pixel_p_s;

2.10创建可容纳不同类型的联合

2.11类型转换

静态转换:此操作不对转换值进行检查;转换时指定目标类型,并需要再转换的表达式前加上单引号

动态转换:$cast( , )

流操作符<<和>>用在赋值表达式的右边,后面带表达式、结构或者数组。流操作符用于把其后的数据打包成一个比特流。操作符>>把数据从左至右变成流,而<<则把数据从右至左变成流。

*数组声明中的下标[256]等同于[0:255]而非[255:0]

2.12枚举类型

enum提供方法来描述抽象变量合法值范围

枚举数据默认(缺省类型)的存储类型为int型(32位有符号二值逻辑),且数值从0开始递增 

枚举类型也可以直接赋初值

enum logic [2:0] {WAITE = 3'b001,LOAD = 3'b010,READY = 3'b100} state_n;

枚举类型是四值逻辑时(logic),直接对枚举值赋值X 、Z也是合法的

如果右侧是枚举类型,可以直接赋值给整型,即int = enum 型式成立

如果右侧是整型,不可以直接赋值给枚举 ,即enum = int 不成立;必须要做类型转换 enum = T’(int);

如果枚举类型没有伴随typedef,那么该枚举类型是一个匿名枚举类型

同do..while实现遍历枚举

枚举类型子程序

2.13常量

Const修饰符 允许在变量声明时对其进行初始化,但不能在过程代码中改变其值;

//const byte colon = “:”;

2.14字符串

string类型可以用来保存长度可变的字符串。单个字符是byte类型。长度为N的字符串中,元素编号从0到N-1;

getc(N)返回位置N上的字节;toupper返回一个所有字符大写的字符串;tolower返回一个小写的字符串;大括号{}用于串接字符串;putc(M,C)字节c写到字符串的M位上;函数substr(start,end)提取出从位置start到end之间的所有字符;

2.15表达式位宽

避免方式A那样由于溢出造成精度受损的情况



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。