SystemVerilog验证 测试平台编写指南 第三章学习笔记(一)

3.1 过程语句

例3.1 新的过程语句和操作符

initial
    begin : example
    integer array[10],sum,j;

    //在for语句中声明i
    for(int i=0;i<10;i++)
        array[i]=i;

    //把数组里的元素相加
    sum=array[9];
    j=8;
    do
        sum+=array[j];
    while(j--);

    $display("Sum=%4d",sum);
    end : example

例3.2 在读取文件时使用break和continue

initial begin
    bit [127:0] cmd;
    int file,c;

    file=$fopen("commands.txt","r");
    while(!$feof(file)) begin
        c=$fscanf(file,"%s",cmd);
        case(cmd)
            "":continue;
            "done":break;
            ...
        endcase //case(cmd)
    end
    $fclose(file);
end

3.2 任务、函数以及void函数

在Verilog中:

1.任务和函数之间最重要的区别是:任务可以消耗时间,而函数不能。

2.函数里面不能待用#100之类的时延语句或者@(posedge clk)、wait(ready)的阻塞语句,也不能调用任务。

3.函数必须有返回值,且返回值必须被使用。

在SV中,允许函数调用任务,但只能在由fork...join_none语句生成的线程中调用。

**对于一个不消耗时间的SV任务,应该把它定义成void函数,这样它就能被任何任务或函数调用。

例3.3 用于调试的void函数

function void print_state( ... );
    $display("@%0t:state=%s",$time,cur_state.name());
endfunction

在SV中,如果想调用函数并且忽略其返回值,可以使用void进行结果转换。有些仿真器如VCS可以不使用void而忽略返回值。

例3.4 忽略函数的返回值

void'($fscanf(file,"%d",i));

3.3 任务和函数概述

*一般情况下,不带参数的子程序在定义或者调用时不需要带空括号()。

*在SV子程序中,begin...end是可选的,task/endtask和function/endfunction已经足以定义子程序的边界。。

例3.5 不带begin...end的简单任务

task multiple_lines;
    $display("First line");
    $display("Second line");
endtask:multiple_lines

3.4 子程序参数

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

例3.6 Verilog-1995的子程序参数

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

例3.7 C语言风格的子程序参数

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

3.4.2 参数的方向

缺省的类型和方向:logic input。

但不建议缺省。

3.4.3 高级的参数类型

ref:ref参数的传递方式为引用。ref参数只能被用于带自动存储的子程序中。

例3.10 使用ref和const传递数组

function void print_checksum(const ref bit [31:0] a[]);
    bit [31:0] checksum=0;
    for(int i-0;i<a.size();i++)
        checksum^=a[i];
    $display("The array checksum is %0d",checksum);
endfunction

*使用了const,则子程序无法修改传递的数组值。

*ref参数在任务中可以修改变量,而且修改结果对调用它的函数随时可见。

例3.11 在多线程间使用ref

task bus_read( input logic[31:0] addr,
               ref   logic[31:0] data);
    //请求总线并驱动地址
    bus.request=1'b1;
    @( posedge bus.grant) bus.addr=addr;
    
    //等待来自存储器的数据
    @( posedge bus.enable) data=bus.data;

    //释放总线并等待许可
    bus.request=1'b0;
    @(negedge bus.grant);
endtask

logic [31:0] addr,data;

initial
    fork
        bus_read(addr,data);
        thread2:begin
            @data;
            $display("Read %h from bus",data);
        end
    join

3.4.4 参数的缺省值

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

3.4.5 采用名字进行参数传递

例3.14 采用名字进行参数传递

task many(input int a=1,b=2,c=3,d=4);
    $display("%0d %0d %0d %0d",a,b,c,d);
endtask

initial begin
    many(6,7,8,9);
    many();       //1,2,3,4使用缺省值
    many(.c(5));  //1,2,5,4
    many(,6,.d(8)); //1,6,3,8
end

3.5 子程序的返回

return语句

从函数中返回一个数组

1. 定义一个数组类型。

2.使用ref参数。

3.将数组包装到一个类中,返回对象的句柄。

3.6 局部数据存储

3.6.1 自动存储

在SV中,模块(module)和program块中的子程序缺省情况下仍使用静态存储。

如果要使用自动存储,则必须在程序语句中加入automatic关键词。

例3.22 在program块中指定自动存储方式

program automatic test;
    task wait_for_mem( input [31:0] addr,expect_data, output success);
        while (bus.addr!==addr)
            @(bus.addr);
        success=(bus.data==expect_data);
    endtask
...
endprogram

3.6.2 变量的初始化 

例3.23 静态初始化的漏洞

program initialization; //有漏洞的版本
    task check_bus;
        repeat (5) @(posedge clk);
        if(bus_cmd=='READ) begin
            logic[7:0] local_addr=addr<<2;
            $display("Local Addr=%h",local_addr);
        end
    endtask
endprogram

存在的漏洞:变量local_addr是静态分配的,在仿真一开始就有了初值。

解决办法:将程序块声明为automatic。或者将声明和初始化分离。

3.7 时间值

3.7.1 时间单位和精度

'timescale

timeunit

timeprecision

3.7.2 时间参数

module timing;
    timeunit 1ns;
    timeprecision 1ps;    
    initial begin
        $timeformat(-9,3,"ns",8); 
        //-9代表ns,3表示3位小数,"ns"时间值后的字符串,8显示数值的最小宽度
        #1 $display("%t",$realtime); //1.000ns
        #2ns $display("%t",$realtime); //3.000ns
        #0.1ns $display("%t",$realtime); //3.100ns
        #41ps $display("%t",$realtime); //3.141ns
    end
endmodule

3.7.2 时间和变量

time类型,64位整型

real类型,实型变量

时间量程和精度,时间会被缩放和舍入。

3.7.3 $time 和 $realtime

      $time为根据所在模块时间精度要求进行舍入的整数。

      $realtime为一个带小数部分的完整实数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值