SV和Verilog的语法类似,和C/C++也有些共性,基本SV可包含Verilog的所有规则,本文会在以下博文内容外做补充,若有相异处下文会特意指出。Verilog语法可参考该链接第1大节。链接:https://blog.csdn.net/qq_39815222/article/details/89601331
1. 数据类型
- 二值逻辑和四值逻辑
编码时一定要注意操作符左右两侧的符号类型要一致
二值逻辑:包括 bit, byte, shortint, int, longint等,均为有符号类型(bit除外);这些类型的值只包含{0,1},目的是模拟计算机验证环境,提高仿真性能,节约空间。若有四值逻辑数给其赋值,x,z会默认被赋值为0,因此二值逻辑数要远离DUT
四值逻辑:包括logic, integer, reg, wire等,均为无符号变量(integer除外);目的是模拟外部物理世界 - logic
用法既拓展了传统的reg型,也可以像wire那样连线,但既然被应用在验证场景中,因此无需关心对应的逻辑是否被综合为寄存器还是线网,只需作为简单的变量赋值即可。
注意:当含有多驱动(multi-drive)的场景是必须使用wire型。 - 动态数组和联合数组
int array[]; //动态数组,compile时长度不确定,simulation时长度确定
array = new[20]; //new分配空间
logic [31:0] array[*]; //联合数组,目的是节约空间 - 队列
概念类似C语言里的队列,用法也类似,可自由插入删除数据,
shortint queue[$] = { 1,2,3 }
queue.insert(1,7); //{1,7,2,3}
queue.delete(1); //{1,2,3}
queue.push_front(6); //{6,1,2,3}
queue.push_back(7); //{6,1,2,3,7}
j = queue.pop_front; //{1,2,3,7} 同理pop_back - 结构体
类似C语言里的结构体,包括概念和用法 - 枚举
enum logic [1:0] {...} state; //可定义z,x状态
2. 语句
- 循环语句
循环语句用于控制执行语句的执行次数,用于在仿真代码中生成仿真激励信号。
for(int i=0; i<=5; i++)... //for循环,相较于verilog,i可以内部定义,且作为局部变量,作用范围只限于for循环
while(i<5) begin...end //while循环,同样存在do...while()
foreach(src[i]) //foreach循环,和for功能类似,但foreach多了可编译的功能,及判断条件里可有变量
src[i] = i;
- randomize()
随机函数
class1 example1 = new;
if( example1.randomize() == 1)...
- 一些关键词
- automatic... ref...
用在function/task赋值
function automatic void f1( ref data ) //此处data和外部定义的data共用同一物理地址,因此两值同时变化
endfunction //若希望内部值的改变不影响外部值的改变,可在内部定义为const ref data - automatic和static
automatic变量类似于软件中的局部变量,在它的作用域生命结束时被销毁回收存储空间
static变量若在仿真开始时被创建,在进程执行过程中自身不会被销毁,且会被多个进程共享。 - inside
if((a==1)||(a==2)||(a==3)) 等价于if( a inside {1,2,3}) - time
描述时间,单位为timescale定义的精度 - rand
rand随机化比较常用
rand bit [7:0] data1; //data1值取0-255中的任意数
randc bit [7:0] data2; //data2取0-255中任意值,但每次取值都不一样,只限于bit和enum类型
constraint range1{ //约束data1范围
data1>100; data1<200;
data1>data2; } - dist { value1 := weight1 value2 :/ weight2 }
划分权重,用在随机化操作中
[1:2]:=40; //每个数权重都是40
[1:2]:/40; //每个数权重是20 - solve...before...
用在随机数产生时,constraint魔窟啊里面
solve y before x //先产生x,再产生y - semaphores
创建对象可复用 - mailbox
创建一个信箱,使通信数据在不同process交换,可理解成fifo
- 一些符号及搭配
- 通配符 .*
可以把相同名字的net和port连在一起
test test1( .a(a), .b(b), .c(c) ); //或者 test test1( .a, .b, .c );
等同于 test t1( .* ); - ==? / !=?
判断符号两边是否像相等或不等,x,z处做通配处理 - ++
SV里面可以用自增符 - 'value 赋值
data0 = 'x //SV中赋值可无需添加b,o,h等代表进制的符号
data1 = '1 //SV中可给某个值赋值全1,注意Verilog中不行 - int'( value)
强制类型转换,int也可以是其他数据类型或unsigned,signed - value1'( value2 )
位宽强制转换,value1是位宽值 - ##
延迟一个时钟周期 - |->
在当前时钟周期
3. 语句块
- program
program可以将设计和验证的调度区域通过显式的方式来安排。
该语句块可在module直接被例化,语句块里面不能出现和硬件相关的过程语句和实例(如always,module等),但是可以有initial,task等块,program与二者的关系类似于C语言里的C文件与主函数,子函数的关系。
program内部定义的变量赋值的方式应该采用阻塞赋值,在驱动外部的硬件信号时应该使用非阻塞赋值。
$exit()强制结束该系统函数所在的program
program execute_test
initial begin
...
end
task task1()
...
endtask
endprogram
- clocking Block
为了避免冒险竞争,通常会把clk驱动的同步信号封装在一个模块里,由interface调用。 - interface
接口作为中间将stimulator / monitor和DUT连接,可以集合多个信号,简化连接,方便调用。
interface可以包含过程语句(always和initial)和连续赋值语句
interface可以定义输入输出端口,若接口对不同连接模块的方向不同,可以将端口定义在modpot中
interface signal_test( input bit clk ); //定义
logic [1:0] A, B;
logic reset;
clocking dram @( posedge clk)
input #1ps A;
input #5
output #6 B;
endclocking
modport user1( output A, input B, reset); //声明的端口可以在不同的modport里定义为不同的输入输出模式
modport user2( clocking cb, input reset); //调用clocking,port输入输出和user1不一样
endinterface
always #5 clk = ~clk;
signal_test.user1 signal1(clk); //声明user1模式
signal_temp signal2( .A(signal1.A), ......); //interface互相直接连接
test test1( signal1 ); //interface与module连接