SV第二章 数据类型


本章节主要是介绍SV中的数据类型,像学习一门新的编程语言一样,从数据类型开始。
相比Verilog,SV提供了新和改进的数据结构。
SV中引进的数据类型和其优点:

  • 双状态数据类型:更好性能,更低的内存消耗
  • 队列、动态和关联数组:减少内存消耗,自带搜索和分类功能
  • 类和结构:支持抽象数据结构
  • 联合和合并结构:允许对同一数据有多种视图
  • 字符串:支持内建的字符序列
  • 枚举类型:方便代码编写,增加可读性

2.1 内建数据类型(自带新增)

Verilog中两种基本的数据类型:变量和线网,四种取值状态:0,1,Z,X。RTL代码使用变量来存放组合和时序值。

2.1.1 逻辑(logic)类型

在Verilog中,有时候分不清使用reg和wire的区别,SV中直接改进reg类型成logic,使其除了作为一个变量,还可以被连续赋值、门单元和模块所驱动。
简单说,任何使用线网的地方都可以使用logic,但对于双向总线设计时不行,即logic不能有多个结构性的驱动
示例:

module logic_data_type(input logic rst_h);
	parameter CYCLE =20;
	logic q,q_1,d,clk,rst_1;
	
	initial begin
		clk=0;
		forever #(CYCLE/2) CLK=~CLK;	//过程赋值
	end

	assign rst_1 = ~rst_h; 	// 连续赋值
	not n1(q_1,q);	// 被逻辑门驱动
	my_dff d1(q,d,clk,rst_l);	//q被模块驱动
	
endmodule

2.1.2 双状态数据类型

相比四状态数据类型,SV中引入双状态数据类型有利于提高仿真器的性能并减少内存的使用量。
最简单的双状态数据类型是bit 无符号。
另四种带符号的双状态数据类型是byte,shortint,int,和longint。

尤其在使用双状态变量来验证连接到被测设计时,被测设计的输出要注意。被测设计试图产生X或Z,这些值会被转换成双状态,但是测试检查不了是转换成0还是1。可以使用($isunknown)操作符,在表达式任意位出现X或Z时返回1
示例:

if ($isunknown (import) ==1)
	$display("@%0t: 4-state value detected on import %b",$time,iport);	// %0t和$time 打印当前时间

2.2 定宽数组

Verilog中是一维的定宽数组reg[7:0] ,SV中提供多样数组类型和功能。

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

// 允许直接给出宽度的方式
int lo_hi[0:15];
int c_style[16];

// 多维数组声明和赋值
int array2[0:7][0:3];
int array3[8][4];
array2[7][3]=1;	// 赋值最后一个元素

若读取越界地址值,返回数组元素类型的默认缺省值

2.2.2 常量数组

初始化:一个单引号加大括号。

int ascend[4] `{0,1,2,3};
int descend[5];

descend = `{4,3,2,1,0}
descend[0:2] =`{5,6,7};
descend = `{4,8};
descend = `{9,8,default:1};

2.2.3 基本数组操作–for和foreach

操作数组的最常见方式是使用for和foreach循环。
$size 函数返回数组宽度。
在foreach循环中只需要指定数组名并在其后面方括号中给出索引变量,便会自动遍历数组元素。
示例:

initial begin
	bit[31:0] src[5],dst[5];
	for(int i=0;i<$size(src);i++)
		src[i]=i;
	
	foreach(dst[j])
		dst[j] = src[j] *2;	// 

end

对于foreach遍历索引多维数组,不是像[i][j]分开放,而是在同一个括号里[i,j]。

int md[2][3] =`{`{0,1,2},`{3,4,5}};
initial begin
	$display("Initial value:");
	// 多维数组正确索引格式
	foreach(md[i,j])
		$display("md[%0d][%0d] = %0d",i,j,md[i][j]);
	
	$display ("new value:");
	// 对最后三个元素赋值5
	md = `{`{9,8,7},`{3{32`d5}}};
	// 遍历
	foreach(md[i,j])
		$display("md[%0d][%0d] = %0d",i,j,md[i][j]);
end

foreach循环会遍历原始申明中的数组范围

2.2.4 基本数组操作–复制和比较

不用循环,对数组进行聚合比较和复制。
示例

initial begin
	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")
	
	// 把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])? "==" : "!=");
end

对数组的算术运算不能使用聚合操作,而是使用循环;对于逻辑运算,只能使用循环或合并数组

2.2.5 同时使用位下标和数组下标

这个不常用。

2.2.6 合并数组

SV中的合并数组既可以用作数组,也可以当成单独的数组。即对某些数据类型,既可以作为一个整体来访问,也可以把它分解成更小的单元,存放方式是连续的比特集合,中间无闲置空间**
示例

// 数组大小定义的格式必须是[msb:lsb],而不是[size]
bit [3:0] [7:0] bytes;	// 4个字节组成32比特
bytes =32'hCafe_Data;
$display(bytes,	// 显示所有32位
		bytes[3],	//显示最高字节“CA”
		bytes[3][7]); // 最高比特位“1”

// 合并/非合并混合数组的声明
bit[3:0][7:0] barray[3];	// 合并
bit[31:0] lw =32'h0123_4567;	// 字
bit[7:0][3:0] nibbles;
barray[0] = lw;
barray[0][3] = 8'h01;
barray[0][1][6] = 1'b1;
nibbles =barray[0];	// 赋值合并数组的元素值

如何选择合并或非非合并数组?
当需要和标量进行相互转换是,使用合并数组;当需要等待数组中变化,必须使用合并数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值