SV笔记
第一章 数据类型
2.1 内建数据类型
对于四值逻辑:
未初始化的变量=x;
未初始化的线网=z
对于二值逻辑:
未初始化的变量=0;
未初始化的线网=0
2.1.1 逻辑(logic)类型
logic类型是在reg类型的基础上改进的。任何使用线网的地方都可以使用logic,但是要求logic不能有多个结构性的驱动,例如在对双向总线建模的时候,此时需要适用线网类型。
module logic_data_type(input logic rst_h);
parameter CYCLE=20;
logic1,q_l,d,clk,rst_l;
initial begin
clk=0;
forever #(CLCLE/2) clk=~clk;
end
assign rst_l=~rst_l;
not n1(q_l,q);
my_dff d1(q,d,clk,rst_l);
endmodule
由于logic类型只能有一个驱动,所以可以使用它来查找网单中的漏洞。把所有信号都声明为logic而不是reg或wire,如果存在多个驱动,那么编译时就会出现错误。
2.1.2 双状态数据类型
相比四个状态数据类型,SV引入的爽状态数据类型有利于提高仿真器的性能并减少内存使用。
双状态数据类型:bit(无符号)、byte、shortint和longint:
//双状态
bit b; //单比特
bit [31:] b32; //32比特无符号整数
int unsigned ui; //32比特无符号整数
int i; //32比特有符号整数
byte b8; //8比特有符号整数
shortint s; //16比特有符号整数
longint l; //64比特有符号整数
//四状态
integer i4; //32比特有符号整数
time t; //64比特无符号整数
real t; //双精度浮点数
使用$isunknown操作符可以在表达式任意位置出现X或Z时返回1。
例2.3 对四状态值检查
if($isunknown(inport)==1)
$dilplay("@%0t:4-state value detected n iport %b",$time,inport);
2.2 定宽数组
2.2.1 定宽数组的声明和初始化
因为几乎所有的数组都使用0作为索引霞姐,所以SV允许只给出数组的宽度的便捷声明方式:
//都表示16个整数
int lo_hi[0:15];
int lo_hi[16];
创建多维定宽数组:
int array2 [0:7][0:3]; //完整声明
int array3 [8][3]; //紧凑声明
int 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,4};
ascend ={4{8}}; //前四个值都是8
descent ='{7,9,default:1} //{7,9,1,1,1}
2.2.3 基本的数组操作——for和foreach
foreach循环中,只需要在指定数组名并在其后面的放括号中给出索引变量,SV会自动遍历数组中的元素。
initial begin
bit[31:0] src[5],dst[5];
for(int 0=0;i<$size(src);i++) //$size返回数组的宽度
src[i]=i;
foreach (dst[j])
dst[j]=src[j]*2;
end
在多维数组中使用foreach的语法foreach 数组名[i,j]。
2.2.4 基本的数组操作——复制和比较
例2.13 数组的赋值和比较操作
initial begin
bit [3:] 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[1:4] %s dst[1:4]",
(src[1:4]==dst[1:4])?"==":"!=");
end
2.2.5 同时使用位下标和数组下标
例2.14同时使用数组下标和位下标
initial begin
bit [31:0] src[5] ='{5{5}};
$display (src[0],, //'b101 或 'd5
src[0][0],, //'b1
src[0][2:1]); //'b10
end
2.2.6 合并数组
声明合并数组时,合并的位和数组大小作为数据类型的一部分必须在变量名前指定。数组大小定义的格式必须得是[msl:lsb],而不是[size]。如下:
例2.15 合并数组的声明和用法
bit [3:0][7:0] bytes;//将4个8bits的数据组装成32bit的数据
bytes=32'haabb_ccdd; //或者bytes={8'haa,8'hbb,8'hcc,8'hdd},因为是一个整体所以要合并赋值
$display ("%h",bytes); //打印整个数组,即32'haabb_ccdd;
$display ("%h",bytes[3]); //最高byte,即8'haa
$display ("%b",bytes[3][7]); //最高bit位,即8'haa=8'b1010_1010中的最高位1
合并和非合并数组可以混合式还用。
例2.16 合并/非合并数组的声明和用法
bit [3:0] [7:0] barray[3]; //一个具有3个类似bytes元素的数组
bit [31:0] lw=32'h 01233_4567; //字
bit [7:0][3:0] nibbles; //合并数组
barray[0]=lw;
barray[0][3]=8'h01;
barray[0][1][6]=1'b1;
nibbles=barray[0]; //复制合并数组的元素值
2.2.8 合并数组和非合并数组的选择
当需要和标量进行相互转换时,使用合并数组会非常方便。例如,你可能需要以自己或字为单位对储存单元进行操作。任何数组类型都可以合并,包括动态数组。队列和关联数组。
如果需要等待数组中的变化,则必须使用合并数组。
2.3 动态数组
动态数组在声明时使用空的下标 [ ],使用时必须调用 new[位宽] 操作符来分配空间。
例2.17 使用动态数组
int dyn[],d2[]; //声明动态数组
initial begin
dyn=new[5]; //分配5个元素
foreach(dyn[j]) dyn[j]=j; //对元素进行初始化
d2=dyn;
d2[0]=5;
$display(dyn[0],d2[0]);
dyn=new[20](dyn); //分配20个整数值并复制,把dyn复制给新的dyn开始的5个元素,并释放dyn原有的所有内存
dyn=new[100]; //分配100个新的整数值,不讲dyn原有的元素复制给新的dyn,而是直接释放
dyn.delete(); //删除所有元素
end
还可以不声明数字元素个数而是直接赋值,这样系统会自动填写元素个数
bit [7:0] mask []='{....,....,....}
2.4 数组方法
- 数组缩减方法:
sum(求和)、product(积)、and、or、xor - 数组排序
- .reverse() //反向排列
- .sort() //生序排列
- .rsort() //降序排列
- .shuffle() //首位颠倒
其中reverse和shffle不能带with,作用于整个数组
- 数组定位
- find、find_index、find_first、find_last、find_first_index、find_last_index
- min()、max()、unique、unique_index
2.5 如何选择数组
-
灵活性
- 动态数组>定宽数组;
- 关联数组:由随机数据或地址产生的生疏分布索引的数组;
- 队列:仿真过程元素数目变化很大的数组,记分板。
-
存储器用量
1、定宽与动态数组:- 元素数<1千:数组类型无所谓;
- 1千<元素数 <1百万:定宽或动态数组;
- 1百万<元素数:需优化算法。
2、队列:
- 存取效率比定宽或动态数组稍差,但在变化很大的应用中可抵消动态数组new的开销
3、动态数组:
- 兆字节的存储器建模
- 速度
- 定宽、动态数组>队列>关联数组;
- 关联数组:存取速度最慢;
- 队列:中间插入或删除元素导致元素搬移,程序会变慢。