关于结构体的内容

关于结构体的内容

结构体使用类似于C语言的语法来定义
结构体使用struct关键字声明。结构体内的成员可以是任何数据类型,包括用户自定义类型和其他的结构体类型。

struct{
	int a,b; //32位变量
	opcode_t opcode;//用户定义类型
	logic [23:0] adress;//24位变量
	bit error; // 一位两态变量
}Instruction_Word;

结构体是变量和/或常量的集合
结构体是一个名称下的变量和/或常量的集合。整个集合可以用结构体名进行引用。结构体内的每个成员也都有一个名称。它用来从结构体中选择成员。结构体成员与C语言中的引用方式相同。

<结构体名>.<变量名>
例如
Instruction_Word.adress = 32'hF000001E;

结构体可以是变量或线网
结构体不同于数组,数组是同类型同尺寸的元素集合,而结构体是不同类型和尺寸的变量和/或常量的集合。另外一个不同是数组元素是通过索引引用,而结构体成员通过的所有成员名称引用。

1、结构体的声明
变量和线网都可以定义为结构体
结构体是变量的集合,可以单独或者作为一个整体进行访问。作为整体时,结构体可以用var关键字声明为一个变量。结构体还可以使用任意Verilog线网类型如wire或tri定义为一个线网。当定义为线网类型时,结构体的所有成员必须都是四态类型的。

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_var;

将结构体声明为变量或线网类型是可选择的。如果未指定,将整个结构体认为是一个变量。
注意,虽然结构体可以被声明为线网类型,但是结构体内不能使用线网类型。多个线网可以用SystemVerilog接口打包成一个组。

自定义和匿名的结构体
可以使用结构体来创建用户自定义数据类型,使用typedef关键字。将一个结构体声明为一个用户自定义类型不分配任何储存区。在声明为用户自定类型的结构体的成员赋值前,必须声明一个这种用户自定义类型的变量。

typedef struct{           //结构体定义
		logic [31 : 0 ] a,b;
		logic[7 : 0] opcode;
		logic[23 : 0] address;
}Instruction_Word_t;
Instruction_Word_t IW; //结构体分配储存区

如果结构体不用typedef声明,它会被当作匿名结构体引用。

 struct{           //结构体定义
		logic [31 : 0 ] a,b;
		logic[7 : 0] opcode;
		logic[23 : 0] address;
}Instruction;

局部和共享结构定义
自定义结构可在模块或接口内定义,在整个设计块中都可以使用。如果一个自定义结构体的定义需要在多个模块中,或作为模块或接口的端口使用,那么结构体定义应该放在包中,并导入到设计块或$unint编译单元域中。

2、结构体赋值
结构体可以使用值列表初始化
结构体在实例化的时候可以对其成员初始化。使用大括号’{}内的一组值,大括号之间的值必须与 成员的个数一致。

typedef struct{           //结构体定义
		logic [31 : 0 ] a,b;
		logic[7 : 0] opcode;
		logic[23 : 0] address;
}Instruction_Word_t;
Instruction_Word_t IW  = '{100,3,8'hFF,0}; //结构体分配储存区

定义结构体常数和结构体参数也使用类似的语法
注意:SystemVerilog数值列表语法不同于C语言

结构体成员赋值
通过引用结构体成员的名称可以对结构体的任意成员进行赋值。

typedef struct{           //结构体定义
		logic [31 : 0 ] a,b;
		logic[7 : 0] opcode;
		logic[23 : 0] address;
}Instr_t;
Instr_t IW; //结构体分配储存区

always@(posedge clock ,negedge resetN)
	if(!resetN)
	begin
		IW.a = 100;//引用结构体成员
		IW.b = 5;
		IW.opcode = 8'hFF;
		IW.address = 0;
	end
	else
	begin
		....
	end

结构体表达式在’{}里面
整个结构体可以使用结构体表达式进行赋值。一个结构体表达式由’{}符号内用逗号隔开的一组值构成,跟结构体初始化一样。大括号内必须包含赋给每一个成员的值。

always@(posedge clock, negedge resetN)
	if(!resetN) IW = '{100,5,8'hFF,0};
	else begin
	...
	end

结构体表达式可以按照顺序或按成员名称列出
结构体表达式中的值可以按照它们在结构体中定义的顺序列出。或者,结构体表达式也可以指定被赋值的结构体成员名称,使用冒号成员名称和要赋的值。当指定成员名称时,表达式的顺序可以是任意顺序。

IW = '{adrress:0,opcode:8'hFF,a:100,b:5};

结构体的部分或全部成员可以被赋一个默认值。
结构体表达式可以通过指定默认值来指定多个成员为一个值。使用default关键字可以将结构体的所有成员指定为默认值。

IW = '{default,0};//设置IW的所有成员为0

使用数据类型的关键字也可以给结构体中特定的数据类指定默认值。default关键字和数据类型关键字使用冒号和其指定的值隔开。

typedef struct{           //结构体定义
		real r0,r1;
		int i0,i1;
		logic [7:0] opcode;
		logic [23:0] address;
}Instruction_word_t;
instruction_word_t IW;

always(posedge clock,negedge resetN)
	if(!resetN)
		IW = '{real:1.0,default:0};
		//指定所有real类型的成员默认值1.0
		//指定其他成员默认值0
	else
	begin
		....
	end

赋给结构体成员的默认值必须与成员的数据类型兼容。也就是说这些值必须能够转换为成员的数据类型。
成员赋值还有一个优先级的问题。default关键字具有最低的优先级,可以被任意指定数据类型的默认值覆盖。指定数据类型的默认值又会被任意显性使用成员的赋值覆盖。

//赋给r0值1.0,r1值3.1415,结构体的其他成员被赋为0
typedef struct{           //结构体定义
		real r0,r1;
		int i0,i1;
		logic [7:0] opcode;
		logic [23:0] address;
}Instruction_word_t;
instruction_word_t IW;
	IW = '{real:1.0,default:0,r1:3.1415};

3、压缩和非压缩结构体
可以使用packed关键字显示地声明一个压缩结构体。压缩结构体按照指定的顺序以相邻的位来储存结构体成员。压缩结构体被当作一个向量储存,结构体的第一成员在向量的最左边。向量的最低位是结构体最后一个成员最低位,其位编号为0

struct packed{
		logic valid;
		logic [7:0] tag;
		logic [31:0] data;
}data_word;

在这里插入图片描述
压缩结构体的成员可以通过成员名引用,也可以使用结构体向量的相应位来引用。

data_word.tag = 8'hf0;
data_word[39:32] = 8'hf0;//同标识符相同的位

注意:压缩结构体只能包含整数值
压缩结构体必须包含压缩变量
压缩结构体的所有成员都必须是整数值。所谓整数值就是可以表示如byte、int这样的向量以及用bit或logic创建的向量值,如果结构体的任何一个成员不能用向量表示,那么结构体都不能被压缩。也就是说压缩结构体不能包含real或shortreal变量、非压缩结构体、非压缩联合体或非压缩数组。
压缩结构体的操作
压缩结构体被看做向量
由于压缩结构体以向量形式储存,对整个结构体的操作也是以向量的形式,因此对向量的算术操作、逻辑操作以及任何其他操作都可以用于压缩结构体。

typedef struct packed{
		logic valid;
		logic [7:0] tag;
		logic [31:0] data;
}data_word_t;
data_word_t packed_in,pack_out;

always@(posedge clock)
	packed_out <= packet_in <<2;

注意,当把’{}符号的一系列值赋给压缩结构体时,列表中的值被赋予结构体的每一个成员,在这种情况下,压缩结构体来对待,而不是一个向量。’{}符号内的值是针对每一个结构体成员的分立值,而不是值的拼接。

有符号的压缩结构体
压缩结构体作为向量使用可以是有符号或者无符号的
压缩结构体可以使用关键字signed或unsigned来声明,这些修饰符影响到整个结构体在算术或相关的操作中,作为一个向量如何识别,但不影响到整个结构体的成员如何识别。结构体的每个成员是有符号的还是无符号,依赖于成员的类型声明。压缩结构体的部分选择始终是无符号的。

typedef struct packed signed{
		logic valid;
		logic [7:0] tag;
		logic [31:0] data;
}data_word_t;
data_word_t A,B;

always@(posedge clock)
	if(A<B)  //有符号的比较
	...

4、通过端口传递结构体
端口可以被声明为结构体类型
结构体可以通过模块和接口的端口传递。结构体必须首先使用typedef定义为用户自定义数据类型,然后才允许将模块或接口的端口声明为结构体类型。

package definitions;
typedef enum{ADD,SUB,MULT,DIV}opcode_t;
typedef struct{
		logic[31:0] a,b;
		opcode_t opcode;
		logic [23:0] adress;
		logic error;
}instruction_word_t;
endpackage

module alu
(input definitions::instruction_word_t IW,
inpput wire  clock);
...
endmodule

还要一种风格可以将包含typedef定义的包显示命名为模块端口定义的一部分,那就是将包导入到$unint编译单元声明域中。还可以在 $unint域中直接定义用户自定义类型。
当一个非压缩结构体通过模块端口传递时,端口两边连接的必须是同一种类型的结构体。在两个不同模块中声明的匿名结构体,即使它们具有相同的名称,同样的成员及名称,但它们并属于相同的结构体类型。
5、将结构体作为自变量传递至任务和函数
结构体可以传递给任务或者函数
结构体可以作为自变量传递至任务和函数。要做到这一点,必须首先使用typedef将结构体定义为用户自定义数据类型,这样任务和函数的自变量才可以声明为这种结构体的类型。

module processor(...);
...
typedef enum{ADD,SUB,MULT,DIV}opcode_t;
typedef struct{
		logic[31:0] a,b;
		opcode_t opcode;
		logic [23:0] adress;
		logic error;
}instruction_word_t;
function alu(input instruction_word_t IW);
...
endfunction
endmodule

当被调用任务或者函数具有非压缩结构体的形式变量时,必须传递完全相同类型的结构体给任务或函数。匿名的结构体,即使具有相同的成员和名称,也不是同种类型的结构体。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

傻童:CPU

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值