编码时一定要注意操作符左右两侧的符号类型要一致二值逻辑:包括 bit, byte, shortint, int, longint等,均为有符号类型(bit除外);这些类型的值只包含{0,1},目的是模拟计算机验证环境,提高仿真性能,节约空间。若有四值逻辑数给其赋值,x,z会默认被赋值为0,因此二值逻辑数要远离DUT四值逻辑:包括logic, integer, reg, wire等,均为无符号变量(integer除外);目的是模拟外部物理世界用法既拓展了传统的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} 在第一个数后面插入一个7queue.delete(1); //{1,2,3}queue.push_front(6); //{6,1,2,3} 在队列前插入6queue.push_back(7); //{6,1,2,3,7} 在队列后插入7j = queue.pop_front; //{1,2,3,7} 同理pop_backstruct {bit [7:0] r,g,b;} pixel;enum logic [1:0] {...} state; //可定义z,x状态SV里的字符串单个字符是用byte类型,且不像C语言,字符串的结尾不带标识符null,因此\0相关操作将无效$display(s.getc(0)); //显示第一个字符的ASCII码$display(s.tolower()); //显示整个字符串的小写kevin$display(s.toupper()); //显示整个字符串的大写KEVINs.putc(s.len()-1, "-"); //将字符-写在字符串的s.len()-1位置上 Kevin-$display(s.substr(2,5)); //提取从位置2到5间的所有字符 bit on[10] ={ 2{1,2,3,4,5}};sum1 = on.sum; //数组求和,积(product),与(and),或(or),异或(xor),最小值(min),最大值(max),相异值(unipue)sum2 = on.sum with (int'(item)); //使用带32比特有符号数显示,在条件语句with中,item是缺省值tq = on.find with(item >3); //找出所有大于3的元素on.reverse(); //数组反向排列,升序(sort),降序(rsort),混排(shuffle)循环语句用于控制执行语句的执行次数,用于在仿真代码中生成仿真激励信号。循环里面一定要有时间在运行,如@(clk)等等,否则会陷入死循环且时间不走动。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多了可编译的功能,及判断条件里可有变量urandom_range(val1, val2) //返回在[val1, val2]区间内无符号的32bit数typedef reg [15:0] opreg_t; //创建新的类型opreg_t等价于reg [15:0]typedef class Packet //创建一个类别名用在function/task赋值,ref参数只能被用于带自动存储的子程序中,若使用automatic,则整个子程序内部都是自动存储的function automatic void f1( ref data ) //此处data和外部定义的data共用同一物理地址,因此两值同时变化endfunction //若希望内部值的改变不影响外部值的改变,可在内部定义为const ref dataautomatic变量类似于软件中的局部变量,在它的作用域生命结束时被销毁回收存储空间static变量若在仿真开始时被创建,在进程执行过程中自身不会被销毁,且会被多个进程共享。if((a==1)||(a==2)||(a==3)) 等价于if( a inside {1,2,3})一般和randomize(value)连用,with后接对value的约束64bit的整数,小数部分会被舍入。描述时间,单位为timescale定义的精度time tdelay = 800fs //0.1psrand bit [7:0] data1; //data1值取0-255中的任意数randc bit [7:0] data2; //data2取0-255中任意值,但每次取值都不一样,只限于bit和enum类型constraint range1{ //约束data1范围 dist { value1 := weight1 value2 :/ weight2 }
solve y before x //先产生x,再产生y创建一个信箱,使通信数据在不同process交换,可理解成fifotest test1( .a(a), .b(b), .c(c) ); //或者 test test1( .a, .b, .c ); data0 = 'x //SV中赋值可无需添加b,o,h等代表进制的符号data1 = '1 //SV中可给某个值赋值全1,注意Verilog中不行强制类型转换,int也可以是其他数据类型或unsigned,signedalways_comb //若需要latch警告,则使用always_latch时序电路,需要敏感信号,且一定是边沿敏感,避免出现flip-flop触发器警告这个块在Verilog中是没有的,当遇到$finish的时候,会进入到final块中。一般用在打印一些信息,注意final块中是不能加延迟#操作的,不然会报错。program将DUT和testbench作了清晰的划分,可以将设计和验证的调度区域通过显式的方式来安排。可以将program看成是按软件的方式运行的,编写该部分代码时完全可以用C语言的思维,无需考虑代码并行执行的情况(除了jork等并行语句),所以非常适合在该块中进行该测试用例产生,发送以及比较数据的接收。可在module直接被例化,但是语句块里面不能出现和硬件相关的过程语句和实例(如always,module等),也不能有其他program语句,可以有initial,task等块。program内部定义的变量赋值的方式应该采用阻塞赋值(软件方式),在驱动外部的硬件信号时应该使用非阻塞赋值(硬件方式)。$exit()强制结束该系统函数所在的program。program中的initial块会在reactive区执行,外部的initial会在active区执行。作为中间模块将testbench和DUT连接,可以将它看成一个“路由器”,集合多个信号,简化连接,方便调用。interface可以包含过程语句(always和initial)和连续赋值语句interface若要与DUT相连需要用四值逻辑,不能用二值逻辑interface可以定义参数、输入输出端口,若接口对不同连接模块的方向不同,可以将端口定义在modpot中。为了避免冒险竞争,通常会把clk驱动的同步信号封装在一个模块里,由interface调用。interface signal_test( input bit clk ); //定义 clocking dram @( posedge clk) modport user1( output A, input B, reset); //声明的端口可以在不同的modport里定义为不同的输入输出模式 modport user2( clocking cb, input reset); //调用clocking,port输入输出和user1不一样signal_test.user1 signal1(clk); //声明user1模式signal_temp signal2( .A(signal1.A), ......); //interface互相直接连接test test1( signal1 ); //interface与module连接可利用package(包)实现在module,interface和program中共享parameter、data、task、class等。即将不同模块的类定义规整到不同package中,在单一的命名空间下,使得分数不同模块验证环境的类来自不同的package,从而解决类的归属问题。reg_pkg::monitor mon1 = new(); //l两个package中同名类monitor的内容不同,实现不同的功能arb_pkg::monitor mon2 = new(); 【免责声明】:本站部分文章为转载或网友发布,目的在于传递和分享信息,并不代表本网赞同其观点和对其真实性负责;文章版权归原作者及原出处所有,如涉及作品内容、版权和其它问题,我们将根据著作权人的要求,第一时间更正或删除。