Systemverilog(绿皮书)学习日记(2)— 过程语句与子程序

一.过程语句

在SystemVerilog中,过程语句(Procedural Statements)用于在模块或任务中执行特定的操作。以下是一些常见的SystemVerilog过程语句:

1.阻塞和非阻塞语句

阻塞和非阻塞赋值语句(Blocking and Non-blocking Assignment Statements):用于将值赋给变量或寄存器。(继承于verilog)

  • 阻塞赋值语句:使用`=`符号,将右侧表达式的值赋给左侧变量,等待右侧表达式计算完成,才进行赋值操作。
  • 非阻塞赋值语句:使用`<=`符号,将右侧表达式的值赋给左侧变量,瞬间进行赋值操作,不受后续语句的影响。

Verilog语法之六:阻塞赋值与非阻塞赋值 - 知乎本文首发于微信公众号“花蚂蚁”,想要学习FPGA及Verilog的同学可以关注一下。一、初步理解阻塞赋值与非阻塞赋值在Verilog HDL语言中,信号有两种赋值方式: (1).非阻塞(Non_Blocking)赋值方式( 如 b <= a; )块…https://zhuanlan.zhihu.com/p/72034401

2.顺序语句

顺序语句(Sequential Statements):用于按顺序执行操作。

  •    `if`语句:根据条件判断执行不同的语句块。
  •     `case`语句:根据表达式值的不同,执行不同的语句块。
  •     `for`循环语句:重复执行一段代码块,可以设置初始化、条件和迭代操作。
  •     `while`循环语句:根据条件重复执行一段代码块。
  •     `do-while`循环语句:先执行一段代码块,然后根据条件重复执行。

3.并发语句

并发语句(Concurrent Statements):用于并行执行操作。

  •  `fork-join`语句:用于创建并发执行的代码块。(其在SV中体现更为丰富,将在如下细化模块进行说明)

fork join辨析https://blog.csdn.net/weixin_48957185/article/details/131897410

  •  `begin-end`语句块:用于分组一系列语句,将其视为一个整体。

4.跳转语句

跳转语句(Jump Statements):用于控制程序的执行流程。

  •    `break`语句:用于退出当前循环。(新增)
  •     `continue`语句:用于跳过当前循环中的剩余语句,继续下一次循环。(新增)
  •     `return`语句:用于退出任务或函数,并返回一个值。

5.其他(等待/事件触发)

此外,SystemVerilog还提供了其他一些过程语句,如延时语句、等待语句、事件触发语句等,可以根据具体需求选择合适的过程语句来实现所需的功能。

SV用法细化 - 事件出发(等待)语句_数字IC验证菜鸟日记的博客-CSDN博客待总结,占坑!!!https://blog.csdn.net/weixin_48957185/article/details/132049696?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22132049696%22%2C%22source%22%3A%22weixin_48957185%22%7D

二.任务和函数(task/function)

1.作用

  • 类似于C语言,函数(function)和任务(task)可以提高代码的复用性整洁度
  • 它们的目的都在于将大型的过程块切分为更细小的片段,而便于阅读代码维护。
  • 相比于大家更为熟悉的函数,SV引入了任务的概念。function与task之间有相同点和不同点

2.区别

 3.使用方法

3.1. 类C的参数声明风格

在verilog中声明一个task的示例如下:

task task_name;
    input  [31:0]   x  ;
    output [31:0]   y  ;
    wire   [31:0]   x  ;
    reg    [31:0]   y  ;

    //      task 内容

endtask

而在system verilog中,除了可以继续使用verilog中task/function的声明风格外,还提供了一种类似C语言的声明风格:

task task_name(
    input        [31:0]   x,
    output logic [31:0]   y    //可以使用logic替代reg与wire
);

  //   task 内容  
endtask

在声明task和function时,可以设置默认的参数值,这样当使用task和function时对应参数缺省时,可以自动带入默认参数。

function multi(
    input int a = 10 ,
    input int b = 2  
);
    int c ;

    return c = a*b ;

endfunction

3.2.形式参数

在高级计算机语言中,形式参数是一种非常好的工具,使用形式参数可以节约内存且很多时候可以使程序更加灵活化,然而在verilog中并没有使用形式参数的方式,而在systemverilog中引入了形式参数。

function void print _checksum(const ref [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

在上例中,关键字ref表示该参数为形式引用。函数体内如果直接改变形式参数,会引起改变量的全局性改变,有时这种改变会比较“危险”,因为我们并不总希望某个函数能改变某个全局变量,特别是该全局变量比较重要的时候。为了解决这个问题,可以使用示例中的关键字const,使用const修饰的形式参数,对于函数来说依然具有形式参数的性质,同时在该函数的作用域内,该参数又可以看作是一个不可改变的常量。如下小节对各位前辈的指导做一个汇总。

3.3.子程序参数

3.3.1.SV中的ref的理解

参考:(以下大部分内容引用自如下帖子)

System Verilog ref参数的理解_systemverilog中ref_簡時光℃的博客-CSDN博客ystemVerilog提供了一个ref关键字作为函数参数的前缀。当使用ref时,表明参数是使用引用传递,'ref’语法类似C++中的引用。有两种情况下使用’ref’做参数比较有意义:第一种情况:由于函数只能有一个返回值(不考虑传统Verilog上的input/output参数端口声明),任务没有返回值。当函数需要返回多个值或者任务需要返回一个以上值的时候,通过引用传递就用得上。第二种情况是运行效率的考虑:当大量的数据需要作为参数传递的时候,值传递效率很低。所有的数据需要在每次函数调用的时候被复制。如_systemverilog中refhttps://blog.csdn.net/weixin_44969124/article/details/108164227system verilog中关于ref 的求解答 - IC验证讨论 - EETOP 创芯网论坛 (原名:电子顶级开发网) -各位兄弟姐妹,小弟在看system verilog的时候,看到这样ref有些不明白,求教一下大家。 1 SystemVerilog也允许通过传值的方式来传递数组参数,这样数组将 ... system verilog中关于ref 的求解答 ,EETOP 创芯网论坛 (原名:电子顶级开发网)https://bbs.eetop.cn/thread-353820-1-1.html

可以看到上面第二个例子中,SV提供了ref关键字作为函数参数的前缀。

当使用ref时,表明参数是使用引用传递,'ref’语法类似C++中的引用。

那么什么时候用到ref参数前缀是必要的呢?(两种情况)

  • 第一种情况:由于函数只能有一个返回值(不考虑传统Verilog上的input/output参数端口声明),任务没有返回值。当函数需要返回多个值或者任务需要返回一个以上值的时候,通过引用传递就用得上。
  • 第二种情况是运行效率的考虑:当大量的数据需要作为参数传递的时候,值传递效率很低。所有的数据需要在每次函数调用的时候被复制。如果参数使用’ref’前缀,可以不需要进行数据复制。但是这样会使得参数的数据容易被函数/任务中的代码修改。此危险可以通过声明ref参数为常量来解决.
     

这里简单举例解释一下,需要结合C的指针概念理解:

task/function xxxxx(ref logic arguments);


endtask/endfunction


上面的task/function,其“形参”是:ref logic arguments

ref的意思你自己已经看过了,那么,这个task/function被调用的时候发生了什么呢?
那就是logic型变量arguments的指针被复制并传递至task/function内部,在task/function内部的一切
对arguments的操作,都是对变量arguments对应的指针,所指向的内容做操作。

        这和c语言的指针是一个概念。也就是说task/function参数是复制一份送入task/function的,这个行为是没有改变的,加了ref,那么参数的指针被复制,不加ref则参数本身被复制,当你对arguments操作的时候,你改变的,是指针所指向地址的内容而非指针本身。(这就是所谓的:在子程序修改ref参数变量的时候,其变化对于外部是立即可见的,因为指针指向的地址没变而该地址本身指向的内容可能改变了。如果sv允许修改指针本身,那么,这句话立刻就不成立了,但是sv限制了对指针本身的修改。)


const限定符限定了指针指向的内容是不可修改的,这个限定符可以防止在task/function内部修改了某个参数,引起意外错误(比如,在其他地方也用了这个指针指向的内容,但他不知道在task/function内部这个指针指向的内容已经被改变了,这是一种非常有用保护措施).

就是说你一加ref,你程序操作的目标数据,都是存储器中同一片地址数据,这样凡是用到这片数据的程序,都会牵一发动全身。

使用注意:见绿皮书P121
1)在需要方法中修改类中参数值得时候,需要在参数前加上ref,尤其是句柄,否则在方法内部对参数的修改 不会被调用该方法的代码看到。P123
2) ref 参数只能被用于带自动存储的子程序中,若程序或模块指明了automatic属性,则其子程序都是自动存储的(P55);如果不希望子程序修改数组的值,则使用const ref类型。

总结:ref

ref 只能被用于带自动存储的子程序中,不希望被修改则用const ref(P55)
在任务里修改变量对调用他的函数随时可见(P123)

3.3.2. SV中的automatic

class中成员和方法默认为动态的即automatic。

program、module、interface、package中函数和任务和变量默认为静态的即static。

首先需要了解如下几个概念:

(1)全局变量和局部变量

在讨论静态变量和动态变量之前,我们先说全局变量和局部变量的概念。

  • 局部变量的生命周期同其所在域,例如function/task中的变量,在方法调用结束后,这些变量的也将消失,所以它们是动态生命周期;
  • 全局变量是从仿真开始到结束一直存在的,例如module中的变量默认情况下全部为全局变量,这也可以理解为module中的变量是硬件电路中实际存在的信号和连接,所以它们是静态生命周期;

(2)静态变量和动态变量

变量可以分为动态(automatic)和静态(static)

静态变量的特点:

  • 该变量将被这个类的所有实例所共享,并且使用范围仅限这个类。
  • 静态变量在声明时就应该对其初始化,它只初始化一次,也就是在仿真0时刻就存在。
  • 可以认为声明在类中的静态成员变量,它是保存在类中,而不是在对象中,它会一直存在的,不会因为对象被销毁而消失。
  • 静态变量可以在类没有被实例化的时候调用,通过 class::static_variable 的方式获取静态变量。

动态变量的特点:

  • 动态变量是类在实例化时,即调用构造函数new()才会初始化。
  • 它的声明周期随着对象而存在,当对象被销毁时,这个变量就也就消失了。
  • 必须要在类被实例化之后才可以调用。

参考:

SV笔记:static 和 automatic 概念及相关规定_sv中function automatic_小汪的IC自习室的博客-CSDN博客目录1 首先总结如下:2 全局变量和局部变量3 静态变量和动态变量4 静态方法和动态方法class中成员和方法默认为automatic,program、module、interface、package中函数和任务和变量默认为静态的。在讨论静态变量和动态变量之前,我们先说全局变量和局部变量的概念。变量可以分为动态(automatic)和静态(static),静态变量的特点:动态变量的特点:如下,使用静态变量count来计数所创建的实例数目:解释代码:static 和 automatic 除了可以修饰类中_sv中function automatichttps://blog.csdn.net/weixin_42294124/article/details/125493766?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-125493766-blog-79015165.235%5Ev38%5Epc_relevant_anti_t3&spm=1001.2101.3001.4242.1&utm_relevant_index=3举个例子:
如下,使用静态变量count来计数所创建的实例数目:

class Transaction;
    static int count = 0;
    int id;
    function new();
        id = count++;
    endfunction 
endclass
 
Transaction t1,t2;
initial begin
    t1 = new(); // t1 中:count = 1,id =0
    t2 = new(); // t2 中:count = 2,id =1
    $display("t2中count=%0d和id=%0d",t2.count,t2.id);
    $display("Transaction中count=%0d",Transaction::count);    
end//Transaction类中:count = 2

解释代码:

每例化一次transaction,count就自加1
第一次在例化时,cout值为0,所以对象 t1 中的 id = 0;
类的构造函数调用完后,使得count自加1,count = 1;
第二次在例化时,cout值为1,所以对象 t2 中的 id = 1;
可以通过Transaction::count的方式,访问类中的静态变量,此时类中的count = 2;
 

(3)静态方法和动态方法

static 和 automatic 除了可以修饰类中的成员变量,还可以修饰 function 和 task,被static修饰的方法称为静态方法。

  • 静态方法的特点:

如果方法被static修饰,那么其内部所有的声明的变量都是 static 的;
静态方法可以在类没有被实例化时被调用,通过 :: 操作符获取,具有全局的静态生命周期;
如果方法被声明为static,那么在仿真开始时即会被创建,且可以被多个进程和方法共享;

  • 动态方法的特点:

如果方法被修饰为 automatic,那么其内部所有的声明的变量默认都是 automatic的;
如果被修饰为 automatic,那么在进入该方法后,automatic变量会被创建,而离开该进程/方法后就被销毁;

如下举例说明了两种方法的区别:

module static_test;
    function automatic int cnt1(input a);  // 函数内所有的变量均为automatic    
        int cnt = 0; //这个变量在每次调用时都会初始化
        cnt += a ;
        return cnt;
    endfunction
    
    function static int cnt2(input a);  // 函数内所有的变量均为static
        static int cnt = 0; //这个static 变量 cnt只会初始化一次
        cnt += a ;
        return cnt;
    endfunction
    
    function int cnt3(input a);  // module中的方法默认为static
        int cnt = 0; //这个static 变量 cnt只会初始化一次
        cnt += a ;
        return cnt;
    endfunction
endmodule
 
initial begin
    $display("%0d",cnt1(1));  // 输出1
    $display("%0d",cnt1(1));  // 输出1
    $display("%0d",cnt2(1));  // 输出1
    $display("%0d",cnt2(1));  // 输出2
    $display("%0d",cnt3(1));  // 输出1
    $display("%0d",cnt3(1));  // 输出2
end

解释代码:

  • 函数声明为automatic或static时,其块内所有的变量都是automatic或static的;
  • automatic类型的变量随函数调用结束后就销毁了,下次再调用时,又会初始化;
  • static类型的变量随函数调用结束后不会被销毁,下次调用时也不需要重新初始化;
  • module内的方法默认是static的;

四.SV中的时间函数和调度(待细化总结)

SystemVerilog中scheduler(调度)SV中调度机理简析https://mp.weixin.qq.com/s/QDUCofxdDAMT8SJvJgaXMASystemVerilog学习之路(6)— 最小时间和时间片_什么叫delta-cycle_Willliam_william的博客-CSDN博客UVM学习之路(6)— SystemVerilog中的最小时间和时间片一、前言delta-cycle(无限最小时间):默认情况下,时钟对于组合电路的驱动会添加一个无限最小时间(delta-cycle)的延迟,而该延迟无法用绝对时间单位衡量,它比最小时间单位精度还小。time-slot(时间片): 在仿真器中敲入命令run 0,即是让仿真器运行一个时间片的时间,在一个时间片中可以发生很多事情,一个时间片里面包含无数个delta-cycle。二、代码实现编写代码如下所示`timescale 1n_什么叫delta-cyclehttps://blog.csdn.net/qq_38113006/article/details/120212477

SV中主要有三个获取仿真时间的系统函数:$time,$stime,$realtime。

三个系统函数的返回值=当前仿真时间/当前作用域的time unit。

Systemverilog系统函数-仿真时间 - 知乎SV中主要有三个获取仿真时间的系统函数:$time,$stime,$realtime。 三个系统函数的返回值=当前仿真时间/当前作用域的time unit。 $time返回的是64bit的integer数; $stime返回的是32bit的无符号整数 $realtime返…https://zhuanlan.zhihu.com/p/459171644#:~:text=SV%E4%B8%AD%E4%B8%BB%E8%A6%81%E6%9C%89%E4%B8%89%E4%B8%AA%E8%8E%B7%E5%8F%96%E4%BB%BF%E7%9C%9F%E6%97%B6%E9%97%B4%E7%9A%84%E7%B3%BB%E7%BB%9F%E5%87%BD%E6%95%B0%EF%BC%9A%24time%EF%BC%8C%24stime%EF%BC%8C%24realtime%E3%80%82,%E4%B8%89%E4%B8%AA%E7%B3%BB%E7%BB%9F%E5%87%BD%E6%95%B0%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%3D%E5%BD%93%E5%89%8D%E4%BB%BF%E7%9C%9F%E6%97%B6%E9%97%B4%2F%E5%BD%93%E5%89%8D%E4%BD%9C%E7%94%A8%E5%9F%9F%E7%9A%84time%20unit%E3%80%82

参考:

SystemVerilog----任务(task)和函数(function)_function systemverilog_一点一点的进步的博客-CSDN博客目录1.概述2.任务和函数的区别3. 任务和函数中的参数传递(值传递和引用传递)4.任务函数返回值5、program块和module模块的区别1.概述类似于C语言,函数(function)和任务(task)可以提高代码的复用性和整洁度。它们的目的都在于将大型的过程块切分为更细小的片段,而便于阅读和代码维护。相比于大家更为熟悉的函数,SV引入了任务的概念。function与task之间有相同点和不同点。2.任务和函数的区别函数function ..._function systemveriloghttps://blog.csdn.net/yh13572438258/article/details/121453101System Verilog 学习笔记2:task/function - 知乎2 Task and Function task和function在verilog中就已经存在,然而systemverilog为了便于工程使用对它们增加了许多新的特性。 1 task与function最大的区别有两点(1)task可以添加消耗时间的语句,而function不可以…https://zhuanlan.zhihu.com/p/110690241SV中的automatic与static_sv automatic_better_xiaoxuan的博客-CSDN博客module breakpoint;int val1;int val2;int result1;//定义在这里,或者定义在未特殊声明的function/task中都是静态的方法function int incr_static(input int a); $display("result1 = %0d", result1); result1 = a + 1; $display("re_sv automatichttps://blog.csdn.net/better_xiaoxuan/article/details/79015165SV笔记:static 和 automatic 概念及相关规定_sv中function automatic_小汪的IC自习室的博客-CSDN博客目录1 首先总结如下:2 全局变量和局部变量3 静态变量和动态变量4 静态方法和动态方法class中成员和方法默认为automatic,program、module、interface、package中函数和任务和变量默认为静态的。在讨论静态变量和动态变量之前,我们先说全局变量和局部变量的概念。变量可以分为动态(automatic)和静态(static),静态变量的特点:动态变量的特点:如下,使用静态变量count来计数所创建的实例数目:解释代码:static 和 automatic 除了可以修饰类中_sv中function automatichttps://blog.csdn.net/weixin_42294124/article/details/125493766?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-125493766-blog-79015165.235%5Ev38%5Epc_relevant_anti_t3&spm=1001.2101.3001.4242.1&utm_relevant_index=3

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Verilog中,for循环的break语句不能直接用于跳出循环。只能用于循环语句破坏循环,跳出循环,不能在执行循环语句。可以使用continue语句结束本次循环,继续下一次循环。例如,在给定的代码中,当i的值在(i>=5)&&(i<8)的范围内时,执行continue,则会执行if((i>=5)&&(i<8)) begin...end循环。如果想要跳出整个循环,可以使用return语句。请注意,return语句可以用于循环语句的结束和task/function的结束。有关更多信息,可以参考附带的Designing Digital Computer Systems with Verilog的PDF文件,或者访问http://www.arctic.umn.edu/vespa。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [systemVerilog过程语句:for循环语句控制/跳转 continue break return](https://blog.csdn.net/qianniuwei321/article/details/127866788)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [用lex与yacc构造汇编器vasm及其指令模拟器vsim](https://download.csdn.net/download/jocks/8161037)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值