SV概述
-
SystemVerilog是IEEE 1364-2005 Verilog标准的拓展
-
此拓展包含了用来实现可综合设计的设计语言特性,也包含了用来对大型设计做验证的验证语言特性
-
SystemVerilog是用来建立一种新的硬件描述和验证语言
-
SV旨在通过一种统一的语言来帮组工程师对大型复杂硬件系统进行建模,并且对其功能进行验证
SV-数据类型
-
Verilog并没有严格区分信号类型,变量(reg)和网线类型(wire)均是四值逻辑(1、0、x(伪稳态)、z(高阻态))
-
SV添加了需要数据类型来帮组设计和验证工程师
-
SV讲硬件信号区分为“类型”和“数据类型”
-
类型:表示该信号为变量(variable)或者网线类型(nets)
-
网线类型赋值只能使用连续赋值(assign,阻塞赋值)
-
变量类型赋值可以是连续赋值(assign,阻塞赋值),也可以是过程赋值(always)
-
-
数据类型则表示该数据是四值逻辑(logic)还是二值逻辑(bit)
-
logic申明时,默认为变量类型(var),除非
wire logic
申明是网线类型 -
bit申明时,默认为变量类型(var),除非
wire bit
申明是网线类型-
bit 1个字节
-
byte 8个字节
-
shortint 16个字节
-
int 32个字节
-
longint 64个字节
-
-
-
有符号无符号
-
logic或者bit构成的向量(vector)是无符号类型
-
integer、byte、shortint、int、longint为有符号类型
-
可以在有符号类型后添加unsigned来表示无符号类型,例如:
-
byte有符号类型,表示数值范围[-128,127]
-
byte unsigned 表示无符号类型,等同于bit[7:0],表示数值范围[0,255]
-
-
在构建验证环境总线功能模型(BFM,Bus-Functional Model)时,无需关注硬件底层逻辑(X或Z值),所以可使用二值逻辑实现
-
同样,SV在与C发生语言交互时,也可以使用二值逻辑来使得两种语言的边界数据传输更为简单
仿真行为
-
四值逻辑变量,如reg、logic、integer,在仿真开始的时候初始值为X
-
二值逻辑变量如bit,在仿真开始时的初值为0
-
如果四值逻辑与二值逻辑发生默认转换,那么Z和X值讲转换为0
-
二值逻辑也可以用来实现可综合电路,只是二值逻辑由于没有X和Z值,因此可能会出现仿真行为同综合电路结果不一致的情况
其他类型
-
SV添加void类型来表示空类型,经常用在函数定义时表示不会返回数值,同C语言的void使用方法
-
SV添加shortreal表示32为单精度浮点类型,同C语言的float;而Verilog的real类型表示双井度浮点类型,同C语言的double
SV-自定义类型
-
通过用户自定义类型,将通过更少的代码来表示更多的功能
-
用户自定义类型使得代码自身的可读性更好
-
通过typedef来创建用户自定义类型
typedef int unsigned uint; // 自定义一个类型是uint,数据类型是无符号的int类型 uint a, b; // 定义两个向量a、b,类型是无符号的int类型
-
通过enum来创建枚举类型
-
枚举类型提供方法来描述抽象变量的合法值范围,其每个之都需要提供一个用户自定义的名字
enum {red,green,blue} RGB; // 定义了一个枚举变量RGB,合法取值:red,green,blue,变量默认值:red typedef enm {red,green,blue} RGB_t; // 自定义了一个类型RGB_t, RGB_t rbg_1; // 通过自定义的类型,定义了变量:rbg_1 RGB_t rbg_2; // 通过自定义的类型,定义了变量:rbg_2
-
默认的枚举类型是int,32位的二值逻辑数据类型,SV允许指明枚举类型的数据类型
enum bit {TRUE, FALSE} Boolean; // 自定义一个变量Boolean,1bit大小,b0表示True,b1表示False enum logic[1:0] {WAITE, LOAD, READY} state; // 自定义一个state变量,类型是logic,占据2个比特位,2'b00表示:WAITE,2'b01表示:LOAD,2'b10表示READY enum logic[2:0] {WAITE = 3'b001, LOAD = 3'b010, READY = 3'b100} state; // 自定义一个state枚举类型变量,类型是logic,占据3个比特位,3'b001表示:WAITE,3'b010表示:LOAD,3'b100表示READY // 枚举类型也可使是四值逻辑,对枚举值赋值X或Z也是合法的 enum logic {ON=1'b1, OFF=1'bz} out;
-
Verilog语言自身不提供枚举类型,因此为了提供类似于枚举类型可实现的便利,不得不采用parameter常量来表示可取值的范围,或者使用
`define
来定义各个合法值对应的宏名称 -
枚举类型赋值相对严格,赋值操作“=”左右两侧应该尽量为相同的枚举类型(枚举类型可以直接转化为整形,整形不能隐式转化为枚举类型)
typedef enum {WAITE, LOAD, READY} states_t; // 自定义一个枚举类型states_t states_t state, next_state; // 定义两个枚举变量,state、next_state int foo; // 定义一个int类型变量foo state = next_state; // state和next_state都是states_t类型,可以相互赋值 foo = state + 1; // state+1计算后是int类型,可以直接赋值给foo state = foo +1; // foo+1计算后是int类型,不能直接赋值给枚举类型state state = state +1; // state+1计算后是int类型,不能直接赋值给枚举类型state state++; // 等价于state = state+1 next_state += state; // 等价于:next_state = next_state+ state,next_state+state计算后是int类型,不能直接赋值给枚举类型next_state
-
-
通过struct来创建结构体类型
-
设计或者验证的数据经常会有逻辑相关的数据信号组,例如一个总线协议的所有控制信号,或者在一个状态控制器中用到的所有的信号
-
SV添加了同C一样的结构体struct,而结构体的成员可以是任何变量类型,包括自动义类型或者其他常量类型
-
例1:
struck { int a,b; // 两个32位的带符号的int类型变量,a和b opcode_t opcode; // 自定义数据类型的变量opcode logic[23:0] address; // 24位的变量address bit error; // 1比特位的变量error } Instruction_Word; // Instruction_Word就是一个结构体变量 //结构体是变量的合集,获取/索引结构体变量中的内部变量如下 Instruction_Word.a; // 索引Instruction_Word中的变量a Instruction_Word.error = 1'b1; // Instruction_Word中的error变量重新赋值为1'b1
-
例2:
typedef struck { int a,b; // 两个32位的带符号的int类型变量,a和b opcode_t opcode; // 自定义数据类型的变量opcode logic[23:0] address; // 24位的变量address bit error; // 1比特位的变量error } Instruction_Word_t; // 自定义了一个结构体类型:Instruction_Word_t,可以用结构体类型来定义变量 Instruction_Word_t IW1; // 使用自定义的结构体类型Instruction_Word_t定义了变量:IW1 Instruction_Word_t IW2; // 使用自定义的结构体类型Instruction_Word_t定义了变量:IW2
-
结构体赋值
// 已有结构体变量:IW,内部变量:a,b // 方式1,索引出内部变量对其进行赋值 IW.a = 100; IW.b = 50; // 方式2:顺序赋值,根据结构体内部变量的顺序依次赋值,有多少个内部变量就要传多少参数值 IW = '{100, 3, 8'hFF, 0}; // 方式3:关键字赋值 IW = '{address:0, opcode:8'hFF, a:100, b:5};
-
-
Verilog无法提供方便的特性来是的用户拓展变量和线网类型
-
SV则提供了特性是的用户可以构建更高抽象层的数据类型
-
为了使代码更已读和维护,通常我们对于自定义的类型,都喜欢添加“_t”的后缀来表示它是一个自定义类型(type)
字符串类型
-
verilog语言对字符串的处理手段非常有限
-
SV引入了string类型用来容纳可变长度的字符串
-
字符串类型变量存储单元为byte类型,1个byte类型占据8个bit位
-
字符串类型长度为N时,其字符成员索引值为0~N-1
-
字符串结尾没有“空字符”
-
字符串内存是动态分配的,无需担心内存空间管理
字符串使用
module testbench_top();
typedef logic[15:0] r_t; // 自定义类型r_t
r_t r; // 自定义类型r_t定义的变量:r
integer i = 2;
string b = ""; // b是空
string a = {"Hi", b}; // a等于字符串"Hi"拼上空,a="Hi"
initial begin
$display("a is %s", a); // 打印:a is Hi
r = r_t'(a); // r是16个比特位的logic变量,a="Hi",两个字符正好占据16个比特位,所以可以强制转换(显式转换)直接赋值
$display("r is %b", r); // 打印:r is 0100100001101001
b = string'(r); // 将r再转为字符串,此时b应该也是"Hi"
$display("b is %s", b); // 打印:b is Hi
b = {5{"Hi"}}; // 将"Hi"重复拼接五次,赋值给b,b="HiHiHiHiHi"
$display("b is %s", b); // 打印:b is HiHiHiHiHi
a = {i{"Hi"}}; // i=2,将"Hi"拼接2次赋值给a;
$display("a is %s", a); // 打印:a is HiHi
a = {i{b}}; // i=2,b=HiHiHiHiHi,将HiHiHiHiHi重复拼接两次赋值给a
$display("a is %s", a); // 打印:a is HiHiHiHiHiHiHiHiHiHi
a = {"My", b}; // 将My和b(HiHiHiHiHi)拼起来赋值给a
$display("a is %s", a); // 打印:a is MyHiHiHiHiHi
a[0] = "W"; // a = "MyHiHiHiHiHi",将a中索引为0的字符"M",修改为"W"
$display("a is %s", a); // 打印:a is WyHiHiHiHiHi
a[0] = "abcde"; // a = "WyHiHiHiHiHi",将a中索引为0的字符"W",修改为"abcde"字符串中最后一个字符
$display("a is %s", a); // 打印:a is eyHiHiHiHiHi
end
endmodule
-
str.len():返回字符串长度
-
str.putc(i, c):将索引为i的字符替换为字符c,等同于str[i]=c
-
str.getc(i):返回第i个字符
-
str.substr(i, j):将索引为i到j的字符串返回
-
str.atoi():将字符串转变为10进制
-
str.atohex():将字符串转变为16进制
-
str.atooct():将字符串转变为8进制
-
str.atobin():将字符串转变为2进制