第三章-过程语句和子程序

本文围绕SV在任务和函数方面的改进展开。介绍了过程语句,如continue和break;放宽了函数调用任务的限制。在子程序参数上,有C语言风格声明、参数方向、高级类型、缺省值等改进。还提及子程序返回、局部数据存储及时间值相关内容,使代码编写更接近C语言,更便捷。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

3.1过程语句

3.2任务、函数和void函数

3.3任务和函数概述

3.3.1在子程序中去掉begin...end

3.4子程序参数

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

3.4.2参数的方向

3.4.3高级的参数类型

3.4.4参数的缺省值

3.4.5采用名字进行参数传递

3.4.6常见的代码错误

3.5子程序的返回

3.5.1返回语句return 

​3.5.2从函数中返回一个数组

3.6局部数据存储

3.6.1自动存储 

3.6.2变量的初始化

3.7时间值

3.7.1时间单位和精度 

3.7.2时间参数 

3.7.3时间和变量

3.7.4$time和$realtime的对比


在做设计验证时,需要写很多代码,其中大部分在任务和函数里面。SV在这方面做了很多改进,使之更接近于C语言,从而使代码的编写更加容易,尤其在处理参数传递上,从而使代码的编写更加容易。

3.1过程语句

SV从C和C++中引入了很多操作符和语句。例3.1展示了一些新的语法结构:

 

SV为循环功能增加考虑两个新的语句。第一个是continue,用于在循环中跳过本轮循环剩下的语句而直接进入下一轮循环;第二个是break,用于终止并跳出循环。看下面例子:

3.2任务、函数和void函数

在verilog中任务和函数之间有明显的区别,其中最重要的一点是任务可以消耗时间而函数则不能。函数里面不能带诸如#100的时延语句或@(posedge clk)的阻塞语句,也不能调用任务。另外verilog中的函数必须由返回值,且返回值必须被使用。

SV对这些限制稍有放宽,允许函数调用任务,但只能由fork...join_none语句生成的线程中调用。

注意,如果你有一个不消耗时间的SV任务,则应该定义为void函数,这种函数没有返回值,这样它就能被任何函数或任务调用。出于灵活性考虑,所有用于调试的子程序都应该定义成void函数而非任务,以便被其他任何函数或任务调用。看下例:

 

在SV中如果想忽略函数的返回值并调用函数,可以使用void进行结果转换。看下例:

3.3任务和函数概述

SV在任务和函数上做了一些小改进吗,使之更像 C或C++的程序。一般情况下,不带参数的子程序在定义或调用时不需要带空括号( )。为了清楚起见,本文的子程序全部带括号。

3.3.1在子程序中去掉begin...end

task...endtask和function...endfunction等关键字就足以定义子程序的边界了。看下例:

 

3.4子程序参数

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

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

 

在SV中可以采用简明的C语言风格,但是注意,必须使用通用的输入类型logic。

3.4.2参数的方向

因为缺省的类型和方向是“logic 输入”,所以在声明时可不必重复。

 

尽管简洁,但是不建议使用这种方式,建议对子程序中的参数声明都带上类型和方向。

3.4.3高级的参数类型

verilog对参数的处理方式简单:在子程序的开头把input和inout的值复制给本地变量,在子程序退出时复制output和inout的值。除了标量以外,没有任何把存储器传递给子程序的办法。

在SV中,参数的传递可以指定为引用而不是复制。这种ref参数类型比input、output和inout更好用。首先,你现在可以把数组传递给子程序。

 

SV允许不带ref进行参数数组的传递,但是这时数组会被复制到堆栈区,这种操作的代价很高;SV的语言参考手册(LRM)规定了ref参数只能被用于带自动存储的子程序中。如果对模块或子程序指明了automatic属性,则整个子程序内部都是自动存储的。上例中也用到了const修饰符,其结果是虽然数组a指向了调用程序中的数组,但子程序不能修改数组的值。如果试图改变数组的值就会报错。

注意,向子程序传递数组时应尽量使用ref以获取最佳性能,如果不希望子程序改变数组的值,可以使用const ref类型。

ref参数的第二个好处是在任务里可以修改变量而且修改结果对调用它的函数随时可见;

在上例中,一旦bus.enable有效,初始化块中的thread2块马上就可以获取来自存储器的数据,而不用等到bus_read任务完成总线上的数据处理后返回,这可能需要若干个周期。由于data是以ref方式传递的,所以只要任务里的data发生变化,@data语句就会触发。如果data声明为output,则@data语句要等到任务结束后才能触发。

3.4.4参数的缺省值

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

可以使用下例所示的方式调用该函数:

3.4.5采用名字进行参数传递

如果有一个带着许多参数的任务或函数,其中一些参数有缺省值,而你只想对其中的一部分参数进行设置,那么可以采用类似port的语法指定子程序参数名字的方式来指定一个子集,看下例:

 

3.4.6常见的代码错误

在编写子程序代码最常见的错误就是,往往会忘记在缺省的情况下参数的类型是与前一个参数相同的,而第一个参数的缺省类型是单比特输入。先看看例3.15所示:

 

两个参数都是整型输入。在编写这个任务时需要访问一个数组,因此又加入了一个数组参数,并使用了ref类型让数组值不被复制,修改后如下:

a、b的方向是与之前的参数是一致的,也就是ref;但是对简单的int变量使用ref通常并无必要,但是编译器对此不会做出任何反应,所以你不会意识到正在使用一个错误的方向类型。如果在子程序中使用了非缺省输入类型的参数,则应明确指出所有参数的方向。如下例:

3.5子程序的返回

verilog中子程序的结束方式简单:在执行完最后一条子程序语句后,程序就会返回调用子程序的代码上。此外,函数还会返回一个值,该值赋给与函数同名的变量。

3.5.1返回语句return 

SV增加了return语句,使子程序的流程控制更加方便。 

上面的任务由于发现错误要提前返回;return也可用于简化函数,看下例:



3.5.2从函数中返回一个数组

verilog子程序只能返回一个简单值,例如比特、数组或向量。在SV中,函数可以采用多种方式返回一个数组。

第一种方式是定义一个数组类型,然后在函数的声明中使用该类型。 如下例所示:

使用上述代码的一个问题是,函数init创建了一个数组,该数组的值被拷贝到数组f5中,如果数组很大,可能会引起性能上的问题。

另一种方式是通过引用来进行数组参数的传递。最简单的办法是以ref参数的形式将数组传递到函数。如下例:

从函数中返回数组的最后一种方式是将数组包装到一个类中,然后返回对象的句柄。

3.6局部数据存储

verilog最初的目的是用来描述硬件,因此语言中的对象是静态分配的。特别是,子程序参数和局部变量被存在固定的位置,而不像其他编程语言那样存放在堆栈里。

3.6.1自动存储 

在SV中,模块(module)和program块中的子程序在缺省情况下依然使用静态存储,如果要使用自动存储,则必须在程序语句中加入automatic关键字。看下例:

 

3.6.2变量的初始化

当你试图在声明中初始化局部变量时,因为局部变量实际上在仿真开始前就被赋予了初值。看下面例子:

 

上面的任务在检测总线5个周期后,创建了一个局部变量并试图把当前地址总线的值作为初值赋给它。由于local_addr是静态分配的,仿真一开始它就有初值,而不是要等到进入begin...end才进行初始化。同样,解决的办法是把程序块声明为automatic.或者也可以按照下面的编码风格,将声明与初始化分离。

3.7时间值

SV有几种新结构使你可以明确的在系统中指明时间值。

3.7.1时间单位和精度 

当你依赖于编译指示语句`timescale时,在编译文件时就必须按照适当的顺序以确保所有的时延都采用适宜的量程和精度。timeuint和timeprecision声明语句可以明确每个模块的时间值,从而避免含糊不清。注意,假如使用这些语句代替`timescale,则必须把它们放入每个带有时延的模块里。

3.7.2时间参数 

通过使用时间函数$timeformat,$time,$realtime来使代码在时间标度上更清楚。$timeformat的四个参数分别是时间标度(-9代表ns,-12代表ps)、小数点后的精度、时间值之后的后缀字符串、显示数值的最小宽度。看下面例子:

 

3.7.3时间和变量

 

3.7.4$time和$realtime的对比

$time的返回值是根据所在模块的时间精度进行四舍五入的整数,不带小数部分;$realtime的返回值是一个带小数部分的完整实数。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值