SV复习(二)

目录

1.过程语句

2.任务、函数以及void函数

3.在子程序中去掉begin…end

4.子程序参数

4.1 C语言风格的子程序参数

4.2 参数方向

4.3 高级的参数类型

4.4 参数的缺省值

4.5 采用名字进行参数传递

4.6 常见的代码错误

5.子程序的返回

5.1 返回return语句

5.2 从函数中返回一个数组

6.局部数据存储

6.1 自动存储

6.2 变量的初始化

7.时间值

7.1 描述时间单位和精度

7.2 时间参数


1.过程语句

SystemVerilog从C和C++中引用了很多操作符和语句。下面就来简单介绍几点。

  • for循环,在for循环中定义循环变量,它的作用范围仅限于循环内部,从而有助于避免一些代码漏洞。for (int i=0;i<10;i++)
  • 自动递增符/自动递减符,++/--,既可作前缀,也可作后缀。
  • 标识符,可以在begin或fork语句中使用标识符,那么在相对应的end或join语句中放置相同的标号。同样,你也可以将标识符放在endmodule、endtask、endfunction等语句中。
initial
    begin:example
        ......
    end:example
  • 循环功能,相比于Verilog,循环功能增加了continue,用于在循环中跳过本轮循环剩下的语句而直接进入下一轮;增加了break,用于终止并跳出循环。

2.任务、函数以及void函数

  在Verilog中,任务task和函数function之间有着明显的区别,其中task可以消耗时间而函数不能。SystemVerilog允许函数调用任务,但只能在由fork…join_none语句生成的线程中调用。
如果有一个不消耗时间的SystemVerilog任务,你应该把它定义成void函数,这种函数没有返回值。

function void print_state(........);
    ......
endfunction

3.在子程序中去掉begin…end

在SystemVerilog中,begin…end变成可选项了,因为task…endtask和function…endfunction这些关键词已经足以定义这些子程序的边界了。

4.子程序参数

SystemVerilog对子程序的很多改进使参数的声明变得更加方便,同时也扩展了参数的传递方式。

4.1 C语言风格的子程序参数

在Verilog中,对一些参数要进行两次声明,一次是方向声明,一次是类型声明。

task my_task;
    output [31:0] x;
    reg   [31:0] x;
    input    y;
    ......
endtask

在SystemVerilog中,可以采用简明的C语言风格,将类型和方向合并,并且在开始进行声明,注意必须使用通用的数据类型logic。

task my_task(output logic[31:0] x,
             input logic y);
            ......
endtask

4.2 参数方向

子程序的参数的缺省值的类型和方向是1比特宽度的logic输入。

task T3;
    input a,b;//参数a和b是1比特宽度的logic输入。
    ......
endtask

4.3 高级的参数类型

  Verilog对参数的处理方式很简单:在子程序的开头把input/inout的值复制给本地变量,在子程序退出时则复制output/inout的值。

在SystemVerilog中,参数的传递方式可以指定为引用而不是复制。采用ref参数类型可以将数组传递给子程序。

function void print_check(const ref bit[31:0] a[]);
    bit [31:0] check=0;
    for(int i=0; i<a.size();i++)
    check^=a[i];
endfunction

ref参数只能被用于带自动存储的子程序中。如果你对程序或模块指明了automatic属性,则整个子程序内部都是自动存储的。(默认)

const修饰符决定了子程序不能修改数组的值。程序内不能改变数组只能看到别的地方对数组的修改

automatic任务里可以修改变量而且修改结果对调用它的函数随时可见。具有简单的信息传递功能

4.4 参数的缺省值

在SystemVerilog中,可以为参数指定一个缺省值,如果在调用时不指明参数,则使用缺省值。

function void print_check(ref bit[31:0] a[],
                          input bit[31:0] low=0,
                          input int high =-1);
    bit[31:0] checksum=0;
    if (high==-1||high>a.size())
    high=a.size()-1;
    for(int i=low;i<=high;i++)
        checksum+=a[i];
endfunction

在函数调用的时候,有以下几种方式:

print_check(a);//a[0:size()-1]中所有元素的校验和——缺省情况
print_check(a,2,4);//a[2:4]中所有元素的校验和
print_check(a,,1);//a[0:1]中所有元素的校验和
print_check(a,2);//a[2:size()-1]从2开始
print_check( );//编译错误:a没有缺省值

4.5 采用名字进行参数传递

类似于模块的端口,可以通过采用类似port的语法指定子程序参数名字的方式来指定一个子集。

task many(input int a=1,b=2,c=3,d=4);
    .......
endtask

函数调用的形式:

many(6,7,8,9); //6 7 8 9指定所有值
many();//采用1,2,3,4使用缺省值
many(.c(5));//1,2,5,4只指定c
many(,6,.d(8));//1,6,3,8混合方式

4.6 常见的代码错误

在缺省的情况下,参数的类型是与其前一个参数相同的,而第一个参数的缺省类型是单比特输入。

task sticky(int a,b);//a、b为两个整型的输入。
task sticky(ref int array[50],int a,b);//默认a、b的方向为ref 错误的方向类型
task sticky(ref int array[50],input int a, b);//a、b为整型输入

5.子程序的返回

5.1 返回return语句

SystemVerilog增加了return语句,使得子程序的流程控制变得更加方便,执行到return,则可以直接返回而不执行其下面的代码。

5.2 从函数中返回一个数组

SystemVerilog中,函数可以采用多种方式返回一个数组。

1)定义一个数组类型,然后在函数的声明中使用该类型。

typedef  int fixed_array5[5];
fixed_array5  f5;

function fixed_array5 init(int start);
    foreach(init[i])
        init[i]=i+start;
endfunction

initial 
begin
    f5=init(5);
    foreach(f5[i])
           $display("f5[%0d]=%0d",i,f5[i]); //f[0]=5 f[1]=6...
end

2)通过引用来进行数组参数的传递。最简单的办法是以ref参数的形式将数组传递到函数里。显然,这种方法是最好理解的一种形式。

function void init(ref int f[5], input int start);
    foreach(f[i])
        f[i]=i+start;
endfunction
int fa[5];
initial
begin
    init(fa,5);
    foreach(fa[i])
    ...
end

6.局部数据存储

  对于一个硬件工程师来说,Verilog语言中所有描述的对象都是静态的,特别是对于子程序参数和局部变量是被存放在固定位置上,而不是像其他编程语言那样存放在堆栈区内。对于递归子程序一类的动态代码没有对应的芯片实现方式,但是在验证过程中,这些动态的中间结果又有着重要的影响,那么我们又该如何对其进行建模呢?

6.1 自动存储

  在Verilog中,如果你试图在测试程序里的多个地方调用同一个任务,由于任务里的局部变量会使用共享的静态存储区域,所以不同的线程之间会串用这些局部变量。这时候,可以指定任务、函数、模块使用自动存储,从而迫使堆栈区存储局部变量。
  SystemVerilog中,模块(module)和program块中的子程序缺省情况下仍然使用静态存储,如果使用自动存储,则必须在程序语句中加入automatic关键词。这样的话,每次调用都使用不同的存储空间。

program automatic test;

6.2 变量的初始化

我们希望在仿真进行了一段时间,再进行下面的操作。给出两个例子,让大家体会一下变量的初始化。

logic[7:0] local_addr=addr<<2;

对于静态变量,仿真一开始它就会有了初始值。可以将其修改为自动存储。静态变量与动态变量最大的差别为静态变量声明即在仿真开始前初始化,且内存不释放,在任务中调用后会一直存储上一次操作的值

logic[7:0] local_addr;
local_addr=addr<<2;

将声明和初始化分开,这样就可以满足题目要求。

7.时间值

7.1 描述时间单位和精度

(1)方式一,'timescale
(2)方式二,timeunit和timeprecision

7.2 时间参数

a. $timeformat(时间标度(-9代表ns,-12代表ps),小数点后的数据精度,时间值之后的后缀字符,显示数值的最小宽度)

 $timeformat(-9,3,“ns”,8);//1.000ns

b. $time

  根据模块的时间精度要求进行舍入的整数。

c. $realtime

  是一个带小数部分的完整实数。

`timescale 1ps/1ps
module ps;
    initial 
    begin
        real rdelay=800fs;    //   0.8ps 以0.800存储
        time tdelay=800fs;   // 1ps舍入后得到1
        $timeformat(-15,0,“fs”,5);
        #rdelay                    //1ps,在作延时时,去时间精度1ps
        $display("%t",rdelay);  // "800fs"
        #tdelay                     //1ps 再次延时1ps
        $display("%t",tdelay);  // "1000fs"
    end
endmodule
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值