SV知识点总结-数据类型
数据类型
1.内建数据类型
逻辑数值类型(四值或⼆值),四值逻辑中的x或z转换为⼆值逻辑时⾃动变为0;
符号:signed和unsigned,bit,logic,reg,net-type⽆符号,注意⽆符号数据与有符号数据间的转换;有符号数据赋给⾼⼀位的⽆符号数据时,符号位宽展⼀位,⽆符号数据赋给⾼⼀位的⽆符号数据时加⼀个0.
位宽。
2.枚举类型
枚举类型可以直接转化为整形,但整形不可以隐式的转换给枚举类型,可以采⽤'()形式,另外可以采⽤$cast( , )进⾏检查。
枚举类型缺省状态下的枚举值:缺省状态从0开始递增(没有特别指明的情况下,枚举类型会被当成int类型存储),可以⾃⼰定义但对第⼀个值的定义最好为0;默认枚举类型是int,也就是32为⼆值逻辑
3.字符串
str.len()/ getc(x) /toupper()/tolower()/putc( , )/substr( , );atoi()/atohex() / atooct()/atobin()字符串转换为整数(返回⼀个32bit整数),对于atoi, 字符串将被看作⼗进制;对于
atohex,⼗六进制;对于atooct,⼋进制;对于atob,⼆进制;itoa()整形转字符串,整
形是⼗进制的。
字符串类型变量的存储单元是byte型,空字符串表⽰为s3={s1.len()+s2.len(){""}}
字符串的拼接与输出:{s1,s2},需要注意的是,字符串如果⼀开始不创建空间,采⽤拼接的⽅式会默认创建空间,但是如果不采⽤拼接时,需要⼀开始开辟空间
$sformat("%s,to,%s",s1,s2)或者$psprintf()
4.结构体
默认⾮组合型结构体,采⽤{};加packed变为组合型结构体采⽤'{}和{}均可;结构体变量索引,采⽤".";结构体默认变量类型是var,但是也可将其声明为wire,将两个输出变成⼀个结构体,与interface对⽐。
⾮组合结构体和组合结构体在赋值⽅⾯的差异和组合型数组和⾮组合型数组相同,并且⾮组合结构体占据的空间⽐组合结构体占据的跟多。如果要做随机化的化,两种类型的变量均要声明为rand,并且针对⾮组合结构体的成员变量可以单独声明为rand(单独随机化成员变量),⽽对于组合型结构体来说,不能单独声明其成员变量为rand,只能整体随机化
⾃定义结构体和枚举类型,添加后缀_t表⽰⾃定义结构类型。在enum/struct类型声
明,如果不加typedef的化,enum{A}B,那么{A}是“匿名类型”,B是枚举变量;添加了typedef的化就变为B就通过typedef变为枚举类型,可在后⾯进⾏复⽤。
6.数组的⼀些操作
6.1组合型数组与⾮组合型数组
维度的概念:⾮组合:wire[7:0] table[3:0]; int a[7:0][3:0];组合:logic[3:0][7:0] data,数组维度声明在变量左侧是组合型数组,在右侧的是⾮组合型数组(仅当两个限定都在中间时是组合,两个限定在⼀块时左边是⾼维度,两个限定不在⼀起时右边是⾼纬度,对于混合型数组,⽐如byte[3:0][1:0]arry3[5:0][7:0]表⽰的是6*8*4*2的四维数组)
赋值:对于组合型数组来说可以把不同维度、不同元素数量的数组间可以进⾏直接赋值(位宽补全或者截取),但是对于⾮组合型数组来说必须必须要求维度和元素相同,否则的化只能对逐⼀元素进⾏赋值。
⾮组合型数组可以采⽤'{}进⾏赋值,但是需要注意这种赋值⼀个'{}代表对⼀个维度赋值,多维时需要多个'{},⽐如'{'h11,'h22,'h33,'h44}就不能赋给bit word [3:0][7:0]⽽要采⽤'{0: '{'h11},1: '{'h22},'{'h33},'{'h44}};可以采⽤foreach对组合型数组和⾮组合型数组之间的转化,两个数组即使维度不⼀样也可以转化,缺少的添0,多的截去,但是不可以直接将两个数组⽤等号转化
UVM:多维数组不⽀持域的⾃动化
6.2数组的复制与⽐较
==和!=结果仅仅是内容相同或者不同,=可以⽤来对数组赋值。在verilog中两个操作数之间存在"=="和“===”,⽽在过程语句块中(initial,always)中对变量赋值存在阻塞赋值(=,串⾏依次并⾏同时,⽴马赋值)和⾮阻塞赋值(“<=”,串⾏并⾏同时执⾏,等待延迟结束后赋值)
6.3遍历数组
for和foreach,对于foreach什么时候⽤d;对于⼆位数组的遍历来说,foreach(sum[i,j])  begi
n…end就等价于foreach (sum[m]) begin foreach(sum[m][n]) begin… end end
foreach轮询数组的顺序:对于队列或者动态数组,循环时是从index索引是从开始;对于定长数组,取决于数组声明的索引顺序,⽐如
arr[3:1]表⽰索引值是从3到1,对于关联数组根据索引值的类型从⼩到⼤
6.4数组运算、定位、排序、随机化
缩进:数组名.sum/product/and/or/xor在对数组进⾏运算过程中需要注意数组中元素的位宽。
定位:数组名.unique(),max(),min(),注意返回的是⼀个int类型的队列⽽不是⼀个标量; 数组名.find_(frist/last_index) with(item>3); d.sum with (item>7)其中item>7返回的是1或者0
排序:数组名.reverse(),sort(),rsort(),shuffle(),注意reverse()和shuffle()作⽤范围是整个数组,因此不能加条件语句with,剩下两个可以加(shuffle对数组元素进⾏随机排序)。
随机化:下⾯的⼏种数组均可以使⽤$urandom_rang($size(arry)-1),从数组中随机选择⼀个元素;对于队列和动态数组可以采⽤$urandom_rang(arry.size()-1)使得随机化的数组在指定范围内平均分布;$random与$urandom之间的差别在于前者返回的是有符号的随机数后者返回的⽆符号的随机数;
对于数组来说,采⽤$urandom()需要对数组的每⼀个元素逐⼀随机化,但是采⽤std::randomize()可以对数组整体进⾏随机化。
7.关联数组
索引类型可以为任何数据类型,对索引值的⼤⼩和顺序都不做要求;存放数据不连续,索引时即使地址不存在该数据也不会报错,建议⽤if 语句,遍历可以采⽤foreach和数名.frist(idx);frist还可以替换成delete,可删除任何⼀个元素;注意idx⽤法,⽐如对于foreach遍历关联数组时,最终显⽰时idx的排序对于整形(关联数组定义为整形)来说是按1234的顺序,对于字符串(关联数组定义为字符串)来说是按abcd的顺序。举例:bit[63:0]assoc[bit[63:0]]
8.对列
不需要new开辟空间,赋值时不需要',q[$]={0,2,5};队列名.push/pop_front/back(),队列名.insert(delete)();对列可以删除单独某个元素,但是动态数组只能全部删除,清空队列和清空动态数组的⽅式类似,采⽤q.delete()或者q={}
9.动态数组
dyn=new[20](dyn),假设动态数组⼀开始有五个值,分别是1-5,那么new[20]新创建了20个元素,并
且前五个元素是之前的1-5后续元素均为0 ,new[dyn1.size()](dyn1);dyn.delete(),dyn=new[0],dyn='{}删除所有元素,null⽆法实现对动态数组的删除,null仅仅当与句柄(类)有关时实现;dyn='{1}也可以,动态数组是与⾮组合型数组类⽐;dyn='{1,2,3,4} 可以不单独开辟空间直接赋值,在赋值过程中开辟空间;
10.定宽数组
int ascend[4] = '{0,1,2,3}
关于数组和队列间的对⽐:
parameter数据类型
(1)关联数组在声明时同队列⼀样⽆需声明⼤⼩,动态数组可以动态创建⼤⼩。
(2)数组存储的时候,合并数组连续存储,⾮合并数组根据每个⾼纬度进⾏单独存储,采⽤logic进⾏存储的时候需要两个bit位进⾏存储,且这两个bit是连续的(针对⾮合并数组种的低纬度)
11.数据间的转换
显⽰转换: ⽐如int'(4.0),将⼀个实数转化为整形,不会检查;$cast(a,b),将b类型转化为a 类型;应⽤:⼦类的句柄可以直接赋值给⽗类,但是⽗类不可以直接赋给⼦类,需要通过$cast函数进⾏操作(也就是需要检查)
隐式转换:不需要转换符号或者系统函数,这种转换需要注意位宽和符号
12.拼接符{}
拼接过程中⼀定要注意位宽,⽐如'h11223344和{'h11,'h22,'h33,'h44}的赋值是不⼀样的,程序会对后⾯的拼接认为每⼀个位宽均是32位;实际上就是组合型数组与⾮组合型数组的赋值,对于⾮组合型数组可以直接采⽤'{}进⾏操作,但是对于组合型数组使⽤{}需要注意位宽,如果不限定位宽会默认每个变量均是32位;注意对列的拼接与对列的取值之间的差异,⼀个⽤{},⼀个⽤[],详细见p30
关于{}的⽤法总结:除了上述⽤法以外,还可以⽤于复制{4{w}};描述覆盖点和仓时;定义枚举类型和结构体时。
13. 系统函数
$dimensions(); $left( , ); $right( , ); $low( , ); $high( , ); $size( ; ); $increment( ; ); $bits()  除了第⼀个和最后⼀个系统函数意外,其他系统函数变量均为两个,左侧为数组名右侧为尺⼨。⽐如:logic [1:2] [7:0] word [0:3] [4:1];$left(word,1); $finish直接退出仿真,$stop暂停仿真。
14. 过程块和⽅法
always/initial
always描述硬件,initial描述软件,两者均⽆法被延迟执⾏(仿真⼀开始就会执⾏),不同initial和always之间也没有顺序⽽⾔。
input/output/inout/ref(ref是引⽤,input output会复制变量)
inout⽅向会在⽅法调⽤中完成⼊⼝处由外部变量到形式参数的拷贝,并且在⽅法退出的时候,由形式参数到外部变量的拷贝,⼀共两次拷贝;ref则是将外部变量本⾝传递进⼊,不在发⽣形式参数到外部变量的拷贝,ref可以理解为指针。如果对某个外部变量进⾏持续跟踪,那么应该使⽤ref⽅向,并且在task中跟踪。
对于ref:有如下应⽤:(1)如同C++中的句柄或者指针,是变量的⼊⼝地址:引⽤数组将其传递到⼦程序;⼦程序修改ref参数变量时,其变化对于外部是⽴即可见的,⽐如在总线上进⾏相关的赋值操作时,如果使⽤output修饰,对参数的赋值往往需要等待总线上这⼀次的任务完成后才可返回,⽽使⽤ref的化,其参数的变化是⽴刻的,常常与fork-join搭配p55;在任务中修改句柄 p123,想修改参数的值的时候,需要在参数前⾯加ref,如果不加ref的化,此参数默认⽅向是input,在⽅法内部对该⽅法的调⽤不会被调⽤该⽅法的代码看到,可能会出现错误;通过引⽤来进⾏数组参数的传递(函数声明时将其声明为数组类型在数组较⼤的时候往往会造成性能上的问题,p59);线程的通讯中将mailbox替换成队列,对队列操作时同样需要⽤ref限定(2)采⽤const ref,在向⼦程序传递数组时,限定⼦程序⽆法修改数组值(3)需要注意线⽹类型⽆法使⽤ref修饰
function/task
(1)function⾮耗时,task内置耗时语句(@event,wait event,#),task可以调⽤function和task,function不建议调⽤task(仅仅能在join none语句成的线程中调⽤);function在声明的时候需要指定返回值,void+return,在内置阻塞语句的情况下,task不能⽤return返回结果,返回数值只能依靠参数列表中的参数;
*需要注意,return可以在task中使⽤,只是不建议这样做,在其中使⽤会⽴刻退出该task(包括void function,使⽤return也会⽴刻返
(2)⼆者均可以在module/package/interface/program中定义
(3)function参数类型默认logic+input
(4)阻塞语句⼀般在task中(阻塞⽅法耗时),⾮阻塞语句task和function中都可以使⽤
automatic/static
(1)在module,program,interface外部定义默认静态变量;module,program,interface内部定义默认+其中function+task外部的情况下任然是静态变量;module,program,interface内部定义的function+task默认是静态⽅法。class内部定义默认动态。
(2)在静态或动态的⼤范围内可以定义相反的⼩范围。
(3)静态变量和⽅法的⽣命周期是从仿真加载到结束和都存在,⽽对于动态变量和⽅法来说,其⽣命周期是随着对象的创建⽽存在的,对象⼀旦销毁,其成员空间也释放。
(4)建议对module和interface中⽅法声明时默认添加automatic,这是由于这些静态⽅法中的变量默认时静态的,在调⽤他们的时候会遇到静态变量内存共享⽽出现不同的线程在同样时间中调⽤相同⽅法引起结果⼲扰的问题。
(5)在声明program时建议直接对program使⽤automatic,否则的化否则在其中定义变量的时候默认是静态的,他从仿真⼀开始就存在,在初始化和多次调⽤中会出现问题(多次调⽤的时候可能会出现覆盖的问题)。
module/interface/program/package
对于program来说,其相当于软件的部分,其中不因该出现与硬件相关的过程语句和实例,例如alway
s,module,interface等,此外其中也不应该出现其他program例化的语句。program内部在定义变量赋值时采⽤阻塞赋值语句,在调⽤外部硬件信号时应该使⽤⾮阻塞赋值语句。其结束有两种情况,⼀种是隐式,等到所有initial语句全部执⾏完后(program中的各个initial并⾏执⾏),程序会结束。另⼀种是显式结束,调⽤$exit。这种情况出现在program中某个initial存在forever语句,也就是该initial语句⽆法结束,在这种情况下程序会⼀直允许,所以需要在这个initial之外的另⼀个initial A中加⼊$exit语句,使得A强制结束。这样的化,等到A执⾏完后program就结束了。如果在program中需要起到类似于always的作⽤,可以通过initial forever来代替。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。