1.SV的数据类型
1.1 内建数据类型(verilog 的数据类型) —> 变量和线网
变量:reg、integer、time、real
线网用于连接设计中不同的部分,但一般情况下用wire
1.2 SV独有的数据类型
1.2.1 logic
logic是对reg数据类型的改进,可以被连续复制、门单元和模块所驱动,但不能有多个结构性的驱动
1.2.2 双状态数据类型
SV 引入的双状态数据类型有利于减少内存的使用
bit 双状态 单比特无符号
byte 双状态 8比特有符号
shortint 双状态 16比特有符号
int 双状态 32比特有符号
longint 双状态 64比特有符号
integer 四状态32比特有符号
time 四状态 64比特无符号
real 双状态 双精度浮点数
$isunknow() 如果检测到表达式的任意一位出现X或Z 返回1
该函数适用于检测被侧设计输出值是四状态,但接收的变量是二状态的,XZ就有可能自动被转化为01 无法被检测
1.3 定宽数组
1.3.1 声明
//给出数组的上下界或者宽度
int array[0:15];
int array[16];
//多维数组
int array[0:7][0:3];//完整声明 (高维度在右边)
int array[8][4];//紧凑声明
//常量数组 (有点类似拼接操作)
int array[4] = '{0,1,2,3};
如果代码从一个越界的地址中读取数据,则会返回数组元素类型的缺省值
四状态返回X 二状态返回0 net返回Z
1.3.2 自带函数
for & foreach(遍历) 不赘述
要注意的是foreach遍历多维数组——> foreach(array[i][j])
复制和比较
可以使用聚合操作对数组进行等于比较和不等于比较
initial begin
bit [31:0] src[5] = '{0,1,2,3,4};
bit [31:0] dst[5] = '{5,6,7,8,9};
if(src == dst) $display("src == dst");//比较
dst = src //复制
end
对数组的算术运算不可以使用聚合操作,应该使用循环
对数组的逻辑运算只能使用循环或者合并数组
1.4 合并数组
个人认为合并数组是一种特殊的定宽数组 和一般的定宽数组主要的差别在于存储方式
1.4.1 声明
合并数组在声明时 合并的位和数组大小必须在变量名前面指定
int array[0:7][0:3];//普通的二维数组
bit [3:0][7:0] parray;//合并数组
1.5 动态数组
编译时给定宽数组分配空间 仿真时才给动态数组分配空间 其出现是为了避免存储空间的浪费
1.5.1&1.5.2 声明和使用
使用空下标,但运行时要使用new函数定义宽度
int dyn[],dyn2[];
initial begin
dyn = new[5];
foreach(dyn[i]) dyn[i] = i;//{1,2,3,4,5}
dyn2 = dyn;
dyn = new[20](dyn);//调整宽度,把已有的值复制进去{0,0,……,0,1,2,3,4,5}
dyn = new[100];
dyn.delete();
end
动态数组 调整宽度的时候是靠sv新建一个指定长度的空间后把原有数据复制进去,对性能有一定影响
可以用动态数组保存元素数量不定的列表 即
int array[] = '{0,2,5,8,4,6}
这种形式的代码是可以的 SV会自动统计其宽度 宽度函数是size()
复制操作前提:基本数据类型相同
定宽数组到动态数组 —> SV调用new[]分配空间和赋值
动态数组到定宽数组 —>宽度需要相同
1.6 队列
1.6.1 定义和声明
链表:增删元素方便,访问元素需要遍历
数组:增删元素需要重新分配空间,访问元素只需使用索引
结合二者优点,1.可以在队列的任何地方增删元素(这是链表特性:分配新空间不需要连续 有索引即可),2.通过索引实现对任一元素的访问
int i;
int q[$] = {2,5,6,8};//声明
intial begin
q.insert(2,5); //在索引2之前插入5 即{2,5,5,6,8}
q.delete(4); //删除索引4的元素 即{2,5,5,6}
q.push_front(8); //在队列最前面插入8 即{8,2,5,5,6}
j = q.pop_back(); //弹出最后一位 j = 6 即{8,2,5,5}
q.push_back(7); //最后面插入7 即{8,2,5,5,7}
j = q.pop_front();//弹出最前面一位 j = 8 即{2,5,5,7}
q.delete(); //{} 也可以对队列赋空值来删除元素,即q = {};
end
在队列的前后存取数据素组很快,在队列中间存取数据需要一定的时间用于搬运数据(队列元素很多的时候 insert()操作慎用)
拼接操作见绿皮书例2.20 类似verilog拼接符号
1.7 关联数组
类似python的字典和java的哈希表
主要用于保存稀疏元素,只为实际写入的数据分配空间
initial begin
bit [63:0] assoc[bit[63:0]],idx=1;//后面的bit[63:0]为索引的数值类型 前面的为索引值的数值类型
//关联数组初始化时使用 : '{};
//在大括号内写入键值对的信息,键值对用:连接;data_as = '{1:20,2:21,3:22};
//对稀疏分布的元素进行初始化
repeat(64) begin
assoc[idx]=idx;
idx=idx<<1;
end
//使用foreach遍历数组
foreach(assoc[i])
$display("assoc[%h]=h%",i,assoc[i]);
//使用函数遍历数组
if (assoc.first(idx))
begin
do
$display("assoc[%h]=%h",idx,assoc[idx]);
while(assoc.next(idx));
end
//找到并删除第一个元素
assoc.first(idx);
assoc.delete(idx);
$display("The array now has %0d elements",assoc.num);
end
1.8 链表
System Verilog支持 但建议用队列
1.9选择存储类型
1.9.1 灵活性
- 定宽或动态数组:存储数组索引规则的数组
- 关联数组:存储数组索引不规则的数组
- 队列:存储元素数目变化很大的数组
1.9.2 存储器用量
- 双状态 合并数组均能减少存储器用量
- 一千到一百万活动元素数组 可使用定宽或动态数组
- 兆字节量级应使用关联数组
1.9.3 速度
- 定宽和动态数组都是存放在连续的存储空间中,访问任何的元素时间都相同,与数组大小无关
- 队列在收尾存取数据几乎没有任何开销,但是在队列中间插入或删除元素需要对其他元素进行搬移以腾出空间。在很长的队列中间插入新的元素,会需要很长的时间
- 关联数组的存取速度是最慢的,因为过程中要有大量算法实现
1.9.4 排序
- 关联数组 : 数组的值不连续且彼此互异
- 队列:元素逐个加入
- 定宽数组或动态数组:元素一次性加入