- 5.1 结构体
- 5.1.1 结构体的声明
- 5.1.2 结构体的赋值
- 5.1.3 压缩和非压缩结构体
- 5.1.4 通过端口传递结构体
- 5.1.5 将结构体作为自变量传递至任务和函数
- 5.1.6 综合指导
- 5.2 联合体
- 5.2.1 非压缩联合体
- 5.2.2 标签联合体
- 5.2.3 压缩联合体
- 5.2.4 综合指导
- 5.3 数组
- 5.3.1 非压缩数组
- 5.3.2 压缩数组
- 5.3.3 使用压缩和非压缩数组
- 5.3.4 声明时对数组进行初始化
- 5.3.5 数组赋值
- 5.3.6 数组复制
- 5.3.7 使用位流转换赋值数组和结构体
- 5.3.8 由数组构成的数组
- 5.3.9 数组中使用用户自定义类型
- 5.3.10 数组通过端口及任务和函数的传送
- 5.3.11 结构体和联合体构成的数组
- 5.3.12 结构体和联合体中的数组
- 5.3.13 综合指导
- 5.4 foreach 数组循环结构体
- 5.5 用于数组查询的系统函数
- 5.6 $bit位宽系统函数
SystenVerilog:
- 加入了结构体类型。
- 加入了联合体类型。
- 在数据如何表示以及数组的操作方面,对Verilog的数组结构进行了拓展。
- 用struct关键字声明。结构体内的成员可以是任何数据类型,包括用户自定义类型和结构体类型。 例子:
struct{ int a,b ; opcode_t opcode ; logic [23:0] address ; bot error ; }Instruction_word;
- 与C语言结构体比较:SystemVerilog不允许使用C语言中的“标记(tag)”。
- 与数组比较:数组是用类型同位数的元素集合,而结构体是不同类型不同位数的变量或者常量的集合。
- 结构体提供了将相关数据集合在一个相同名称下的机制,数据的每一部分可以通过名称来单独引用,整个组也可以作为整体引用。
- 变量(未指定则默认为变量)
var struct{ logic [31:0] a,b; logic [7:0] opcode; logic [23:0] address; } Instruction_word_var;
- 线网
wire struct{ logic [31:0] a,b; logic [7:0] opcode; logic [23:0] address; } Instruction_word_net;
- typedef
typedef struct{ logic [31:0] a,b; logic [7:0] opcode; logic [23:0] address; } Instruction_word_t;
- 匿名结构体
struct{ logic [31:0] a,b; logic [7:0] opcode; logic [23:0] address; } Instruction_word;
- 局部或者共享结构体 在模块或者接口内定义。
- 初始化 使用 '{} 内的一组值在实例化结构体时初始化。大括号内值的个数与成员的个数一致。
Instruction_word_t IW = '{100, 3, 8, 8'hff, 0};
- 成员赋值
- 通过成员名称赋值
nstruction_word_t IW; ... IW.a = 100; IW.b = 3;
- 将结构体表达式赋值给结构体 跟初始化格式一样按顺序赋值,或者指定名称赋值,但是不能混用。
nstruction_word_t IW,IW1; ... IW = '{100, 3, 8, 8'hff, 0} ; //1. 按照顺序赋值 IW1 = '{a:100, address:0, b:3, opcode:8'hff}; //2. 按照名称赋值
- 结构体表达式的默认值 结构体的部分或者全部成员可以被赋一个默认值,default优先级最低。
truct{ real [31:0] a,b ; logic [7:0] opcode ; logic [23:0] address; } Instruction_word; nstruction_word_t IW,IW1; ... IW = '{default:0} ; //设置IW所有成员为0。 IW1 = '{default:0, real:1.0}; //由于default优先级最低,设置IW所有real类型成员为1.0,其他为0。
- 通过成员名称赋值
-
压缩结构体的声明 使用packed关键字。
struct packed { logic valid; logic [ 7:0] tag ; logic [31:0] data ; }data_word;
压缩结构体被当作向量存储,所以可以通过读写向量的方式访问结构体成员。 |valid-----|tag-----|data-----| |40--------|39------|31------0|
-
压缩结构体的操作 对向量的算术操作,逻辑操作以及任何其他操作都可以用于压缩结构体。
-
有符号的压缩结构体
- 压缩结构体可以用关键字signed或unsigned声明成有符号或者无符号的,这只影响到整个结构体在算术或者相关操作。
- 成员有符号还是无符号依赖于成员的类型声明。
- 对压缩结构体部分选择相当于对变量的部分操作,始终是无符号的。
结构体必须首先使用typedef定义为用户自定义数据类型,才允许将模块或接口的端口声明为结构体类型。 至于如何声明typedef定义的结构体,可以在package中,也可以在$unit中,然后导入。
5.1.5 将结构体作为自变量传递至任务和函数结构体必须首先使用typedef定义为用户自定义数据类型,才允许将结构体作为自变量传递至任务或函数。
5.1.6 综合指导非压缩和压缩结构体都是可综合的。
5.2 联合体- 联合体只存储一个元素,但这个元素可以有多种表示方法,每种表示可以是不同的数据类型。
union { int i; int unsigned u; }data; ... data.i = -5;//意思是data现在的表示方法是int; $display("data is %d",data.i); data.u = -5;//意思是data现在的表示方法是int unsigned; $display("data is %d",data.u);
- 同样的,有typedef修饰的是自定义联合体,没有的是匿名联合体。
- 典型应用:当一个值可能有几种不同的数据类型,但是每次只使用一种类型。
- 联合体允许用多种方法来使用同一块存储空间。
- 可以包含任意变量类型。
- 抽象类型,不可综合。
- 如果非压缩联合体读取的成员不是上次写入的成员,那么读出的值不确定。
- 一个联合体可以声明为 tagged:
union tagged { int i; real r; } data;
- 标签联合体包含一个存储“标签”的隐含成员,它代表存储数值的最后一个联合体成员的名称。 标签表达式:
data = tagged i 5;//在data.i中存5,并设置隐含标签
- 如果 读出或者普通表达式写入值的成员 与 标签表达式值上次写入的成员 不一致,会产生错误消息。
d_out = data.r; //错,读取成员与隐含标签不一致 data.i = 7;对,与隐含标签一致
- 压缩联合体成员位宽必须相同。
- 压缩联合体可综合。
- 只能存储可以用向量表示的值。
- 可以用一种格式写入,以另一种方式读取。比如成员1为64位宽向量,成员2为长度为8的字节数组,以字节方式写入,以向量方式读出。
- 压缩的标签(tagged)联合体:位宽可以不同,必须可以用向量表示。
只有压缩联合体可综合。
5.3 数组 5.3.1 非压缩数组 Verilog-1995Verilog-2001SystemVerilog只允许定义一维数组,数组声明仅限于reg、integer、time允许多维数组,允许除event类型外的所有变量或者线网类型用于数组声明非压缩数组允许任何数据类型一次只能访问一个元素一次只能访问一个元素可以引用整个数组或者其中一段声明时需要指定数组的地址范围声明时需要指定数组的地址范围允许只指定维度大小,而不用指定开始和结束地址注意:简化的数组声明不能用于向量声明。
int array[1024];//C语言
integer [31:0] array[0:1023];//Verilog
logic [31:0] array[1024];//SystemVerilog
logic [32] array[1024];//错,简化的数组声明不能用于向量声明。
SystemVerilog:
- 与verilog一样,非压缩数组的各个元素的存储是独立的,可能不连续。
- 复制非压缩数组时,等号两边必须具有同样的构架和类型。
多维压缩数组的存储方式:
logic [3:0][7:0] data;
|data[3][7:0]----|data[2][7:0]----|data[1][7:0]----|data[0][7:0]----| |31--------------|23--------------|15--------------|7--------------0|
- 压缩数组的数据类型 只有位形式的数据类型才可以被压缩。
- 引用压缩数组
- 作为整体
- 位选择
- 部分选择
logic [3:0][7:0] data ; wire[31:0] out = data ;//作为整体 wire sign = data[3][7] ;//一位 wire [3:0] nob = data[0][3:0];//部分 byte high_byte ; assign high_byte = data[3] ;//部分 ligic [15:0] word ; assign word = data[1:0] ;//部分
- 非压缩数组用于:
- byte、int、integer、real、非压缩结构体、非压缩联合体以及其他非位形式的数据类型。
- 通常每次只访问一个元素的数组,模拟存储器以及抽象数据类型。
- 压缩数组用于:
- 由只有1位的数据类型组成的向量
- 需要字段访问的向量。
-
压缩数组初始化
logic [3:0][7:0] a = 21'd0;//向量赋值 logic [3:0][7:0] b = {16'hz,16'h0};//拼接操作符 logic [3:0][7:0] c = {16{2'b01}};//复制操作符
-
非压缩数组初始化
int d1 [0:1][0:3] = '{'{1,2,3,4},'{5,6,7,8}}; int d1 [0:1][0:3] = '{2{1,2,3,4}};//复制操作符{}前不用加' d1[0][0] = 1; d1[0][1] = 2; ... d1[1][2] = 7; d1[1][3] = 8;
-
为非压缩数组指定默认值
int a1 [0:7][0:1023] = '{default:8'h55};
按照上面给定的索引方式
- 非压缩数组赋值 Verilog:
- 给一个元素赋值。
- 给一个元素的1位或者部分位赋值。 SystemVerilog新增:
- 用一个值序列’{}给整个数组赋值。
- 用一个值序列’{}给数组的一段赋值。
- 使用default给整体或者部分赋默认值。
byte a [0:3][0:3]; a[1][0] = 8'h55; a = '{'{0,1,2,3},'{4,5,6,7},'{0,1,2,3},'{4,5,6,7}}; a[3] = '{8'h55,8'h55,8'h55,8'h55};
- 压缩数组赋值
- 数组的一个元素。
- 整个数组(向量)。
- 数组的一部分。
- 数组的一段(多个相邻的子域)。
byte [1:0][1:0][7:0] a; a[1][1][0] = 1'b0; a = 32'h55555555; a[1][0][3:0] = 4'h5; a[0] = 16'h5555; a = {16'bz, 16'b0};
- 压缩数组到压缩数组
- 大位宽赋值给小位宽:高位忽略。
- 小位宽赋值给大位宽:高位填0。
- 非压缩数组到非压缩数组 与压缩数组到压缩数组一样
- 非压缩数组到压缩数组 需要位流转换
- 压缩数组到非压缩数组 需要位流转换
- 位流转换将非压缩数组临时转换成向量形式的位流,这个临时向量可以赋值给其他数组。
- 源数组与目标数组的总的位数必须相同,每个元素宽度可以不同。
- 适用情况:
- 把非压缩数组赋值给不同结构的非压缩数组。
- 把非压缩数组赋值给压缩数组。
- 把压缩数组赋值给非压缩数组。
- 把结构体赋值给压缩或者非压缩数组。
- 把定宽或动态宽度的数组赋值给动态宽度数组。
- 把结构体赋值给另一个不同结构的结构体。
typedef int data_t[3:0][7:0];//非压缩类型
data_t a;//非压缩类型;
int b [1:0][3:0][3:0];//非压缩数组
a = data_t'(b);//位流转换
5.3.8 由数组构成的数组
非压缩维度的索引先于压缩维度,从左到右:
logic [3:0][7:0] mixed_array [0:7][0:7][0:7];
//优先级:(4) (5) (1) (2) (3)
//---------------------------------------------
mixed_array [0] [1] [2] [3] [4] = 1'b1;
//优先级: (1) (2) (3) (4) (5)
5.3.9 数组中使用用户自定义类型
用户自定义类型(typedef)可以作为数组的元素。
typedef logic [3:0] nibble;//压缩数组
nibble [31:0] big_word;//压缩数组,等同logic [31:0][3:0]big_word;
typedef nibble nib_array[0:3];//非压缩
nib_array compound_array [0:7];//非压缩,等同logic [3:0]compound_array[0:7][0:3];
5.3.10 数组通过端口及任务和函数的传送
VerilogSystemVerilog只允许压缩数组通过模块端口传送,并可以传送进/出任务和函数。允许任何类型及任意维数的数组通过端口传送,并可以作为任务和函数的自变量传送。
5.3.11 结构体和联合体构成的数组
数组可以包含结构体或者联合体。
typedef struct packed {
logic [31:0] a;
logic [7:0] b;
}packet_t;
packet_t [23:0] packet_array;
5.3.12 结构体和联合体中的数组
- 结构体和联合体可以包含压缩或非压缩数组。
- 压缩的结构体和联合体只可以包含压缩数组。
数组和数组的赋值都是可综合的。
5.4 foreach 数组循环结构体- foreach循环的自变量是数组名,它后面是方括号内用逗号隔开的循环变量列表,
int sum [1:8][1:3];
foreach (sum(i,j))
sum[i][j] = i + j;
- 哪个维度不带变量名表示将跳过这个维度。
int sum [1:8][1:3];
foreach (sum(i))
sum[i][0] = i;
5.5 用于数组查询的系统函数
- $dimensions(array_name);//返回数组维数
- $left(arrar_name, demension);//返回指定维度的最高有效位数(msb)
- $right(array_name, dimension);//返回指定维度的最低有效位数(lsb)
- $low(array_name, dimension);//返回指定维度的最低位数
- $high(array_name, dimension);//返回指定维度的最高位数
- $size(array_name, dimension);//返回指定维度元素的总个数
- i n c r e m e n t ( a r r a y n a m e , d i m e n s i o n ) ; / / 对 于 指 定 的 维 度 , 如 果 increment(array_name, dimension);//对于指定的维度,如果 increment(arrayname,dimension);//对于指定的维度,如果left>=$right,返回1;反之返回-1
类似与C语言的sizeof函数。
//$bit(expression);
bit [63:0] a;
wire [3:0][7:0] c [0:15];
$bit(a);//返回64
$bit(c);//返回512