天天看点

system verilog 工程杂记

  1. 子类和父类的方法调用问题:(参考绿皮书P227)

B extend A;A和B都有方法 fun,且fun前面都有virtual修饰:此时根据句柄指向的对象类型来决定调度谁的fun;

如果fun前面没有virtual修饰:则会根据句柄类来决定调用谁的fun,而不是对象类型;

多个具有继承关系的类的方法,共用同一个名字的现象即为:“多态”

  1. vcs 只支持   bit   [10:0] XXX;
  2. 不支持:byte    [10:0] XXX;   这种编译会报错
  1. vcs编译某一个filelist文件:vcs  -sverilog  -f  xxx.f  xxx.log

上述编译完成后会生成:simv文件;再输入./ simv进行仿真;

1)GVIM:

   1、:iab lw liu wei  编辑简写;.vimrc配置

   2、gvim窗口:命令模式:vsp  说明:左右分屏

   3、:E   打开目录页

   4、:bd    :w回退窗口

2)linux:

    ssh 主机名   //切换主机 or 服务器

3)verdi波形中需要下载数组信号时:在仿真中加入 $fsdbDumpMDA()或者按下图加上“”“+all” 

system verilog 工程杂记

4)根据用例名字和随机种子生成波形文件名: 

在top_tb里面加入:

reg [1000:0] casename;
    initial begin //  12 27
        if($value$plusargs("TESTNAME_FSDB=%s",casename)) begin
            $display("TESTNAME_FSDB = %s ",casename);
            $fsdbAutoSwitchDumpfile(1024,casename,10);
        end
        $fsdbDumpvars(0,top_tb,"+all"); // +all for strunct
        $fsdbDumpMDA();
        $fsdbDumpon();
    end
           

在run/Makefile加入:

RUN_OPTS += +TESTNAME_FSDB=$(tc)_$(seed).fsdb #3-14
           

取int数据中的某一些比特;

system verilog 工程杂记

资料来源:公众号-芯片学堂

1.initialize RNG

(1)初始化RNG是产生随机数的开始,用来给RNG初始化随机种子。

(2)每一个模块实例(module instance)、接口实例(interface instance)、程序块(program)和包(package)实例都有属于自己的初始化RNG,在不指定随机种子的情况下,默认的随机种子根据不同编译器的实现决定的。

2.hierarchy seeding

(1)分层分配随机种子是随机稳定性的重要机制。

(2)在创建新的线程或者实例化对象的时候,父线程使用的RNG的下一个随机值会作为这个新线程或者新对象的RNG的随机状态,即作为新的种子传递下去。

3.thread & object stability

(1)SV中将程序(program)、模块(module)、接口(interface)、函数(function)、任务(task)等这些独立的块叫Process。

(2)每个Process都有自己的RNG。每个RNG都有自己的随机状态(random state)。

(3)可以通过process::self()这个静态方法获取当前Process的RNG句柄,再通过句柄调用get_randstate()方法来获得随机状态。不同的仿真工具返回来的随机状态的值的表现方式可能会不一样,但基本都是一段看起来没有规律的字符串,这个字符串表示下一个要产生的随机数的值。

注:在复现一个执行失败的测试用例的时候,不要改动之前布下的种子,也不要改变程序中线程和对象创建的顺序,避免更改了分层随机种子的顺序。

在sv/verilog中,我们常用的是整数(int, longint),小数可以用(real),对小数的处理大致分为三种:

1. 四舍五入(如果除数和被除数均为整数,可以通过乘以1.0来实现)

2. 向上取整:系统函数$ceil(164*8/28) = 47

3. 向下取整:通过系统函数$floor实现;$floor(164*8/28) = 46

$ceil和$floor只參數接受int 和real類型,不接受bit類型或int unsigned;

参考链接:【systemverilog】对小数的处理_lbt_dvshare的博客-CSDN博客_systemverilog 浮点数

随机一个数组:

int    ai_port[] ;
int    port_tmp[8] = '{0,1,2,3,4,5,6,7,8};


ai_port = new[7]; //初始化
ai_port_tmp.shuffle(); //打乱数组顺序,再去取前面的一部分;
foreach (ai_port[i])   ai_port[i] = ai_port_tmp[i] ;
ai_port[$] = 9 ; //对数组的最后一个元素给特定值

void'(std::randomize(qid_port) with {qid_port inside {ai_port}); //qid_port将在ai_port里面的几个值平均随机;即使里面重复多次的数,也会是均匀随机,参考绿皮书P142 例子6.14
//上面数组ai_port,也可以是队列的形式
           

$display的选项:

参考:Systemverilog中$display()常见打印选项

system verilog 工程杂记

https://blog.csdn.net/jiujiusousou/article/details/104523536

语句 含义
\n 换行符
\t 制表符
\v 垂直制表符
\f 换页符
\\ \字符
\" " 字符
\a %字符
%d 十进制输出
%b 二进制输出
%o 八进制输出
%h 十六进制输出
%e 指数形式输出
%f 十进制表示方法输出实数
%g 十进制或者指数表示方法输出实数
%s 字符串输出
%c ASCII码输出
%m 输出层次名
%v 输出网线类型变量的强度
%t 输出当前时间
%p 可以打印数组(还有unpacked structures, arrays, and  unions.)
IEEE Std 1800™-2012 :The %p format specifier may be used to print aggregate expressions such as unpacked structures, arrays, and  unions.

常用形式: 

system verilog 工程杂记

小数计算场景:

int   i_tmp=3;
real  r_real_ab;
real  r_real_a = 1;
real  r_real_b = 2;

i_tmp = real'(1/3); // 结果为0
r_real_ab = real'(2)/real'(3); // 结果为:0.6667
i_tmp = 4/3;// 结果为: 1
r_real_ab = 1/3; // 结果为0
r_real_ab = r_real_a/r_real_b; // 结果为:0.5
           
int          ai_test_array[10];
          int          a = 4;
          int          b = 9;

          ai_test_array [1]    =  $ceil(real'(9)/real'(4));// result is 3
          ai_test_array [2]    =  $ceil(real'(9)/4)       ;// result is 3
          ai_test_array [3]    =  $ceil(9.0/4.0);  // result is 3 
          ai_test_array [4]    =  $ceil(9/4.0)  ;  // result is 3
          ai_test_array [5]    =  $ceil(9/4*1.0);  // result is 2
          ai_test_array [6]    =  $ceil(1.0*9/4);  // result is 3
          ai_test_array [7]    =  $ceil(9/real'(4));  // result is 3 
          ai_test_array [8]    =  $ceil(9/real'(a));  // result is 3
          ai_test_array [9]    =  $ceil(real'(b)/4);  // result is 3
           

字符串类型:

SystemVerilog引入了一个字符串类型(string),它是一个大小可变、动态分配的字节数组。

字符串类型变量的声明语法如下:

     string variable_name [=initial_value];

如果在声明中没有指定初始值,变量会被初始化成空字符串(“”)。字符串文本由引号(“”)包围并且拥有自己的数据类型。对字符串文本的长度没有预定义的限制,一个字符串文本必须存在一个单行中,除非新的行紧跟着一个反斜杠(\)。

字符串操作方法:systemverilog 字符串类型 - burlingame - 博客园 (cnblogs.com)

system verilog 工程杂记
https://www.cnblogs.com/zhiminyu/p/12945749.html(16条消息) SystemVerilog——字符串_红茶绿茶和奶茶的博客-CSDN博客_systemverilog 字符串
system verilog 工程杂记
https://blog.csdn.net/qq_40893012/article/details/114456786

SV文件写入:()

integer   fit_dut,fid_refm;// 声明文件的句柄

fid_refm = $fopen("data_refm.txt","w");
fid_dut  = $fopen("data_dut.txt","w");
$fwrite(fid_refm,"%0h",exp_tr_0);
$fwrite(fid_dut,"%0h",act_tr_0);

//......
$fclose(fid_refm); //已验证 可行
$fclose(fid_dut);
           

静态变量和动态变量:

静态变量只初始化一次;动态变量每次调用都会初始化;

静态变量的初始化时不可综合的;动态变量的初始化是可综合的,前提是这些动态变量只是函数内部使用,不会传递到函数外面;

变量在声明时,可以直接初始化;(int   mi_abc = 99;)(在SV中内嵌初始化在仿真时刻0之前执行)(initial块则是在仿真时刻0执行)

静态task/function内的变量,缺省时也是静态的;

模块一级的变量都是都是静态的,不能显示的声明为static或automatic;(参考黄皮书P44)

在verilog中:module、begin......end块、fork.......join块以及非自动的task和function中,缺省时都为静态存储;

SV向后兼容verilog:所以上述:module、begin......end块、fork.......join块以及非自动的task和function中,缺省时都为静态存储;(这就是为什么fork.....join_none开启多个线程时,需要用到动态变量来辅助的原因吧TBD)

函数调用自身:递归函数;

一般系统函数和系统任务是不可以综合的;

@(posedge  bus.clk);(这个好像会多花一拍时间)(10368ns)

@bus.monitor_cb;(这个会少花一拍时间)(10367ns)

实际场景中:如果没有统一,采用混用的话,可能会出现输出数据的顺序不一致

这两种触发有什么区别吗?

第一:@(posedge  bus.clk)采的信号仿真器认为是上升沿前的数据,@bus.monitor_cb仿真器认为是触发沿后的数据;(如果所有的采样信号都已加入clocking block,那么采样的数据均为时钟沿前的数据)

第二:后一种方式在时钟信号名发生改变后只需要修改interface文件即可

 执行顺序顺序问题:

fork

    begin // thred1:
        repeat(1)  @(posedge   v_glb_intf.clk);
        $display("it is not #0ns");
    end

    begin // thred2: #0ns
        repeat(1)  @(posedge   v_glb_intf.clk);
        #0ns;
        $display("it is #0ns");
    end

    begin // thred3:
        repeat(1)  @(posedge   v_glb_intf.clk);
        repeat(2) #0ns;
        $display("it is 2 #0ns");
    end

join_none

//#0ns 可以用来调整代码块的执行顺序;上述伪代码:会先执行线程1,再执行线程2,最后再执行线程3
           

task和function的区别:

1、function不能执行耗时语句,可以用return返回值;

2、task能执行耗时语句,不可以用return返回值;

常见的耗时语句@event 、wait event 、 #delay

function和task的区别——SV,SystemVerilog_小小verifier的博客-CSDN博客_sv中function和task的区别

system verilog 工程杂记

https://blog.csdn.net/SummerXRT/article/details/117955497?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-2-117955497.pc_agg_new_rank&utm_term=function+systemverilog+task%E5%8C%BA%E5%88%AB+%E4%B8%8E&spm=1000.2123.3001.4430

system verilog 工程杂记

对某一个信号打拍(就是refm的信号延迟多少拍后再与DUT的信号比对) 

//beat_num 要打的拍数
int        pipe_mem_bp[]; //pipe refm_bp //solve refe_mode syn DUT signal;
pipe_mem_bp = new[beat_num];
foreach(pipe_mem_bp[i])  pipe_mem_bp[i] = 0;// initial array[]

while(1) begin
        @(posedge v_glb_intf.clk); // 
        for(int i = 0; i < (beat_num -1); i++)    pipe_mem_bp[i+1] = pipe_mem_bp[i]; // to achieve pipe beat_num clk
        pipe_mem_bp[0] = refm_bp;

        if (pipe_mem_bp[beat_num-1] != dut_bp) begin
            //do somethng
        end
end
           

pre_randomize()和post_randomize;

当调用 obj . randomize () 的时候,它首先调用 obj 的 pre_randomize () 方法以及它的所有被使能的随机对象成员。接下 来 pre_randomize () 会调用 super . pre_randomize () 。在新的随机值被计算并赋值后, randomize () 会调用 obj 的 post_randomize () 方法以及它的所有被使能的随机对象成员。接下来 post_randomize () 会调用 super . post_randomize (); 用户可以在任何类中过载 pre_randomize () 方法以便执行对象被随机化之前的初始化和预处理。 用户可以在任何类中过载 post_randomize () 方法以便执行对象被随机化之后的清除、打印诊断、以及后处理。 如果这些方法被过载,那么它们必须调用对应的父类方法,否则它们在随机化之前和之后的处理步骤会被忽略。 pre_randomize()和 post_randomize()方法不是虚拟的。然而,因为它们会被虚拟的 randomize()方法自动调用,所 以它们看上去像是虚拟的。

system verilog 工程杂记

给所有bit赋值:data = 'b1;  data = {32{1'b1}};