首页 理论教育 FPGA系统设计-任务和变量使用技巧

FPGA系统设计-任务和变量使用技巧

时间:2023-10-20 理论教育 版权反馈
【摘要】:任务之后要书写任务名。参变量的作用就是把参数作为任务和外界的沟通桥梁,可以把参数传入或传出任务。例6.61:调用任务b。例6.62:这个例子语句1开始定义了任务,语句7调用了任务,本意是任务里生成out的波形,通过调用任务把out波形传送给clk。例6.63:例6.64:调用上一例的任务read_data。例6.65:从下面这个例子,学习automatic类型任务和非automatic类型任务的区别。相应的任务的结束时刻就不同于任务的起始时刻。

FPGA系统设计-任务和变量使用技巧

Verilog有个概念叫作任务。任务的功能类似于c语言里的子程序。在模块里可以调用任务。所以,任务的意义相当于代码段的共用。

任务的基本结构如下:

输入输出声明;

任务的具体执行过程;

我们先看一个例子,大致了解一下任务的基本结构。

例6.60:编写任务b。

一个任务,在书写完task之后,要立即书写endtask。任务里可以定义输入和输出。

任务的后面可以定义automatic或不写。automatic的意思就是任务里调用的所有局部变量都是动态分配的。也就是说,如果同时调用了几个任务,这些调用的局部变量不会相互之间串扰,毕竟它是动态分配的。比如像上面这个例子,task之后没有写automatic。如果加上automatic,则每次调用这个任务,都会为任务里的参数单独分配存储空间。

任务之后要书写任务名。这个例子里就是取名b。

这个例子里定义了输入c和输出d。任务可以没有参变量,可以有一个参变量,也可以有多个参变量。参变量的作用就是把参数作为任务和外界的沟通桥梁,可以把参数传入或传出任务。任务里定义的输入,就是外界要传递进去给任务的东西。任务里定义的输出,就是任务要传出去给外界的东西。任务里还可以定义inout的参变量,它既可以作为输入,也可以作为输出。

在任务里定义的这些参数(例如这个例子的integere),都是局部参数,只能任务里看得到;只有在任务外定义的参数,才是作用于全局的。这个和c语言很类似。

然后就是任务的具体的执行过程。

既然要用到任务,初衷都是想少写一些重复调用的代码。那么,任务里最经常要做的事就是for循环了。

我们看一下如何调用上面这个任务。

例6.61:调用任务b。

因为任务b有外界给它的输入c,也有要传递出去的输出d,所以调用的时候先声明寄存器give_to_c和get_from_d。give_to_c作为输入值传递进入任务给c,从任务获得输出d传递到任务之外的get_from_d。在任务中声明输入和输出的先后顺序(先c后d),就决定了在调用任务的时候,谁是传递给输入c,谁是输出d传递出来的。

任务里也许会涉及时序控制,所以,任务的调用会经历一段时间的延迟才会有返回值

例6.62:

这个例子语句1开始定义了任务,语句7调用了任务,本意是任务里生成out的波形,通过调用任务把out波形传送给clk。调用任务的结果是clk=0。语句3~语句5的结果都没有显示在clk。原因在于:只有当任务的调用结束时,才通过参变量把值赋值给输出。

可行的一种方法是把out定义为全局变量,也就是把语句2写到语句1之前。(www.xing528.com)

例6.63:

例6.64:调用上一例的任务read_data。

例6.65:从下面这个例子,学习automatic类型任务和非automatic类型任务的区别。

假设任务的调用是依次按照下面这个流程的:

首先从语句9开始模块t,执行到语句10、语句11,reset赋值为低电平0。

语句12调用任务auto_comparison。从语句1开始执行。这是自动任务。依次执行到语句4。由于之前shifter未赋初值,所以语句4执行的结果就是语句15。继续执行语句5,因为刚才reset为0了,所以if的条件为真,执行语句6,shifter赋值为0001。执行语句7,shifter为0010。执行语句8,执行的结果就是语句16。

语句12调用完了,执行到语句13,reset赋值为1。

语句14又调用任务auto_comparison。

从语句1开始执行。依次执行到语句4。由于这是个自动任务,每次调用自动任务auto_comparison都会给reg类型变量shifter分配单独的存储空间。所以语句4执行的结果就是语句17。继续执行语句5,因为刚才reset为1了,所以if的条件为假,不执行语句6,直接执行语句7,shifter为xxxx左移一位,依然是xxxx。执行语句8,执行的结果就是语句18。

这就是自动类型任务的含义。

当然了,如果该任务不是automatic的,没有关键字automatic,也就是语句1写为“taskauto_comparison;”,则这是个静态类型的任务,执行的结果如下:

也就是说,对于静态任务,reg类型shifter的内容是静态的,每一次使用完,是多少就是多少,就放在那,下回调用还是调用它,调用过程该修改它的就修改它,修改完是多少就是多少,每一次调用都依然使用上一次修改后的值。

这就是静态类型任务的含义。

任务调用有几个特点:

(1)在一个任务里,我们会定义一些局部的变量,如果没有特别的声明,这些局部变量默认都是局部的,同时也是静态的。这就意味着,如果在同一时刻对这个任务进行两次调用,两个调用将使用的是分配给这个变量的同一处物理地址,这就是静态的含义。这也意味着使用的时候要防止冲突和意想不到的情况。

(2)我们可以在一个任务里使用上一级模块定义的寄存器,因为所谓“上一级”就意味着,这个上一级相对于这个任务来说就是全局。

(3)任务内部也许会包含延迟语句。延迟的意思就是说如果执行任务的调用,执行的过程就不会是瞬时。相应的任务的结束时刻就不同于任务的起始时刻。

(4)任务的调用过程和汇编语言的中断是类似的,如果想中途结束任务,可以使用disable语句跳出中断。任务中断后,会返回之前调用任务的地方继续往下执行。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈