SystemVerilog
数据类型
内建数据类型
延续Verilog的语法,增加新的数据类型。
在verilog中,数据类型分为两类:variable和net型
variable:reg,integer,time等
net:wire,wor,wand等
在systemVerilog中,**数据类型有两个属性:**type、datatype
type表明该数据是variable或net型
datatype表明数据的值是4值或2值。
vartable型数据既可以是4值逻辑也可以是2值逻辑,但是net型只能是4值逻辑。
SV推出了新的数据类型logic、bit
logic为4值逻辑:0、1、x、z
bit为2值逻辑:0、1(在某种不需要不定值x和阻塞值z的情况下使用,节省空间)
4值逻辑:integer、reg、logic、net-type(wire等)
2值逻辑:byte、shortint、int、longint、bit
有符号类型:byte、shortint、int、longint、integer
无符号类型:bit、logic、reg、net-type
默认大小和值: bit:1为2值的整数
byte:8位2值的整数,类似char类型
shortint:16位2值整数,类似short类型
int:32位2值整数,类似int型
longint:64位2值整数,类似longlongint类型
在systemverilog中,使用关键字logic类型代替reg类型,logic单独使用是位4值逻辑。
logic类型的数据赋给bit型:
高位宽的数据赋给低位宽:从高到低舍弃,不定值x变为0;
低位宽赋给高位宽:从高到低补充0;
常用数据类型
数组
一维数组
一维数组:int lo_hi[0:15]; 16个整数[0],[1],...,[15]
int c_style[15]; 16个整数...
多维数组:int array[0:1][0:2]; 完整声明,直接在声明时定义大小
int array[2][3]='{'{0,1,2},'{2,3,4}};
初始化前访问数组返回值:logic:x,bit、int:0;
如果试图从一个越界的地址中读取数据,那个SV将会返回数组元素的缺省值。对于一个元素为四状态类型的数组,例如logic,返回的是X,而对于双状态类型,例如int或bit,则返回0。这适用于所有的数组类型,包括定宽数组、动态数组、关联数组和队列,也同时适用于地址中含有X或Z的情况。线网在没有驱动的时候输出Z。
合并数组
合并数组
当需要把数据当成一个整体访问时,同时又可以把它分为更小的单元,此时需要合并数组。例如一个32bit的寄存器,有时候可以当成4个8bit的数据,有时候可以堪称一个无符号数据。
bit [3:0][7:0] bytes;
bytes = 32'haabb_ccdd;
$display("%h",bytes); //整个32位bit,32‘haabb_ccdd
$display("%h",bytes[3]); //最高位byte,8’haa
$display("%h",bytes[3][7]); //最高bit位,8'haa=8'b1010_1010;
其中Byte[3]中的数据aa是byte型,相当于c中的char
*
非合并数组
非合并数组
不需要把数组当作一个整体来访问
声明:bit[7:0] b_unpack[3]; //3字节
动态数组
动态数组
在执行程序前不知道数组宽度,可以用[]预留空定义动态数组
数组为空,但是调用前必须用new[]来指定宽度
int dyn[],d2[]; //声明2个动态数组
initial begin
dyn=new[5]; //为数组dyn分配5个空间
foreach(dyn[j]) dyn[j]=j; //遍历dyn,并且把0-4赋给dyn
d2=dyn; //把dyn数组复制给d2
d2[0]=5; //把d2中的0位置元素更改为5
dyn=new[20](dyn); //复制dyn并且为dyn分配20个空间,把dyn的前5个空间用dyn[0-5]覆盖
dyn=new[100]; //分配100个新的元素,旧值不存在
dyn.delete(); //删除数组
end
常量数组
常量数组
常量数组用一个‘+{}来初始化数组
int ascend[4] = `{0, 1, 2, 3}; // 对4个元素进行初始化
int descend[5];
descend[0:2] = `{5,. 6, 7}; // 为前3个元素赋值
ascend = `{4{8}}; // 四个值全是8
descend = `{9, 8, default:1}; // {9, 8, 1, 1, 1}
使用数组下标和位下标
src[5]=00000101,00000101,00000101,00000101,00000101
src[0]:00000101
src[0][0]:00000101中最后一位1
src[0][2:1]:00000101中10
关联数组类似于哈希表,一个索引对应一个数组值
基本数组操作
foreach循环
对多维数组使用foreach时,并不是像[i][j]这样把每个下标分别放在不同的括号里,而是用逗号隔开放在同一个方括号里,像[i, j],如foreach(md[i, j]) begin ... end
bit[31:0] src[5],dst[5];
for(int i=0;i<$size(src);i++)
src[i]=i; //初始化src
foreach(dst[j])
dst[j]=src[j]*2 //dst的值是src值的2倍
如果不需要便利数组中所有的维度,可以在foreach的循环中忽略它们,如下所示把一个二维数组打印成一个方形的阵列。它在外层循环中便利第一个维度,然后再内层遍历第二个维度。
复制
数组的复制可以直接用数组名进行复制
比较
在不使用循环的情况下,也可以利用“==”或者“!=”来比较数组的内容,不过结果仅限于 内容相同或者不相同。
bit [31:0] src[5] = ‘{0,1,2,3,4},
dst[5] = ‘{5,4,3,2,1};
if (src==dst) $display("src == dst"); // 比较数组
else $display("src != dst");
dst = src; // 数组复制
src[0] = 5; // 只改变一个元素的值
//所有元素是否相等
$display("src %s dst",(src==dst)?"==":"!=");
//使用数组片段对第1-4个元素进行比较
$display("src[1:4] %s dst[1:4] ",(src[1:4]==dst[1:4])?"==":"!=");
若要得到数组中的每个元素是否相等,可以用for循环遍历数组的每一个元素,并进行比较。
bit [31:0] src[5] = ‘{0,1,2,3,4},
dst[5] = ‘{5,4,3,2,1};
dst = src; // 数组复制
src[0] = 5; // 只改变一个元素的值
for(int i=0; i<$size(src); i++) begin
if (dst[i]==src[i])
$display("src[%d] == dst[%d]",i,i);
else
$display("src[%d] != dst[%d] ",i,i);
end
若要得到数组中的每个元素是否相等,可以用foreach循环遍历数组的每一个元素,并进行比 较。
bit [31:0] src[5] = ‘{0,1,2,3,4},dst[5] = ‘{5,4,3,2,1};
dst = src; // 数组复制
src[0] = 5; // 只改变一个元素的值
foreach(dst[i]) begin
if (dst[i]==src[i]) $display("src[%d] == dst[%d]",i,i);
else $display("src[%d] != dst[%d] ",i,i);
end
关联数组
int arr[string];
arr=`{"1s":'h12',
"2nd":'h23'}
arr["1s"]
队列
队列的基本操作
-
队列的声明是使用带美元符号的下标:[ ] 。队列元素的编号从 0 到 ]。队列元素的编号从0到 ]。队列元素的编号从0到。队列的常量中只有大括号而没有数组常量中开头的单引号。注意不要对队列使用构造函数new[ ]。
-
队列在声明以后,只能通过索引或方法两种方式进行初始化。
-
队列的方法有insert 、pop_front、push_back、delete等。
-
如果把 放在一个范围表达式的右边,则代表最大值,如果 放在一个范围表达式的右边,则代表最大值,如果 放在一个范围表达式的右边,则代表最大值,如果放在一个范围表达式的左边,则代表最小值。队列的常量不需要” ’ “初始化.
队列的插入和删除可以用函数也可以用**“位拼接符{}”**
结构体
关键字struct的功能少,它只是一个数据的集合,其通常的使用的方式是将若干相关的变量组合到一个struct结构定义中。
struct {bit [7:0] r, g, b;} pixel; // 创建一个pixel结构体
//为了共享该类型,通过typedef来创建新类型
typedef struct {bit [7:0] r, g, b;} pixel_s;
//为了便于硬件使用,还有压缩格式:
typedef struct packed {bit [7:0] r, g, b;} pixel_s;
非压缩结构体
typedef struct{
bit [7:0] r;
bit [7:0] g;
bit [7:0] b;
} pixel_t;
压缩结构体
typedef struct packed{
bit [7:0] r;
bit [7:0] g;
bit [7:0] b;
} pixel_t;
typedef struct {
bit [7:0] r;
bit [7:0] g;
bit [7:0] b;
} pixel_s;
pixel_s my_pixel; // 声明变量
my_pixel = '{'h10,'h10,'h10}; //结构体类型的赋值
typedef struct packed{
bit [7:0] r;
bit [7:0] g;
bit [7:0] b;
} pixel_s;
pixel_s my_pixel; // 声明变量
体会压缩结构体中 带' 和 不带' 的赋值的区别
my_pixel = {8'h10, 8'h10, 8'h10}; //结构体类型的赋值 相当于拼位操作符
my_pixel = '{8'h10, 8'h10, 8'h10}; //结构体类型的赋值 常量赋值方式
非压缩结构体
压缩结构体
r [23:16] g [15: 8] b [ 7: 0]
- 在压缩结构体中,不加“ ‘ ”的“ {} ”赋值相当于拼位操作符,如果赋值时不加位宽,则数据为默认结构体中属性的类型位宽,例如bit [7:0] g,赋值’h10,则十六进制的10相当于10000,只能取到后两位00,因为bit类型默认是2位宽。
union联合—图片加载失败
- 结构体联合时,需要注意的是两个结构体指向了同一块区域,当一个结构体的值改变之后,其实是它所指向的那片内存中的值改变了,故另一个结构体打印出来的是已经改变的值,还需要注意的是不论在何时,SV代码中变量的类型、默认类型和位宽都需要注意。
枚举类型
- 枚举类型创建一种相关但是独立的常量,例如状态机中的状态或者指令中的操作码。可以自动为列表中的常量分配不同的数值,其值必须在{min,max}中,注意定义枚举类型时的位宽所能比表示的最大值和最小值,其默认是int型常量。
typedef enum{init,decend,idle} fsmstate_e;
//声明枚举类型,其中init默认为0,decend为1,idle为2.
fsmstate pstate;创建一个枚举类型的变量
typedef enum{first=1,second,third} ordinal_e//初始化错误
ordinal_e postion;//postion缺省值为0,故first赋值为1是错误的。
typedef enum{ad=0,first=1,second} ordinal_e;
oedinal_e postion;//初始化正确。