System Verilog 学习笔记 (一) 数据类型1

发布于:2022-10-24 ⋅ 阅读:(380) ⋅ 点赞:(0)

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;//合并数组

这个写的比较好【system verilog】非合并数组、合并数组、混合数组和多维数组的小探讨_尼德兰的喵的博客-CSDN博客_systemverilog 合并数组前言来了的话点个赞吱一声在走呀~~~因为需要解决一个问题,所以决定对合并数组/非合并数组以及混合场景进行进行一下探索。问题已知一个多维混合数组的定义为:bit [3:0][7:0][15:0] Array [3:0][7][6];那么当我们写下Array[2][3][2][2] = xxxx;的时候,到底是对哪个位置赋值了??话不多说,直接看解答好啦~最后的...https://blog.csdn.net/moon9999/article/details/104190800

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 排序

  • 关联数组 : 数组的值不连续且彼此互异
  • 队列:元素逐个加入
  • 定宽数组或动态数组:元素一次性加入

网站公告

今日签到

点亮在社区的每一天
去签到