
本文共 4190 字,大约阅读时间需要 13 分钟。
目录
一.task和function说明语句的区别
task和function说明语句分别用来定义任务和函数。利用任务和函数可以把一个很大程序模块分解为许多较小的任务和函数便于理解和调试。输入、输出和总线信号的值可以传入或传出任务和函数。
任务和函数往往是大程序模块中在不同地点多次用到的相同程序端。任务和函数有些不同,主要的不同有以下4点:
- 函数只能与主模块共同用一个仿真时间单位,而任务可以定义自己的仿真时间单位
- 函数不能启动任务,而任务能启动其它任务和函数
- 函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量
- 函数返回一个值,而任务则不返回值
函数的目的是通过返回一个值来响应输入信号的值。任务确能支持多种目的,能计算多个结果值,这些结果值只能通过被调用的任务的输出或总线端口送出。Verilog模块使用函数时是把它当作表达式中的操作符,这个操作的结果值就是这个函数的返回值。
二.任务(task)
如果传给任务的变量值和任务完成后接收结果的变量已定义,就可以用一条语句启动任务。任务完成以后控制就传回启动过程。如任务内部有定时控制,则启动的时间可以与控制返回的时间不同。
任务可以启动其它任务,其它任务又可以启动别的任务,可以启动的任务数是没有限制的,不管有多少任务启动,只有当所有的启动任务完成以后,控制才能返回。
1.任务定义
定义语法为:
任务:task <任务名> ; <端口及数据类型声明语句> <语句1> <语句2> ... <语句n> endtask 语句n> 语句2> 语句1> 端口及数据类型声明语句> 任务名>
2.任务调用及变量传递
调用任务并传递输入/输出变量的声明语句的语法如下:
<任务名> (端口1,端口2,...,端口n); 任务名>
任务定义如下所示:
task my_task; input a,b; input c; output d,e; ... <语句> //执行任务工作相应的语句 ... c = foo1; //赋初始值 d = foo2; //对任务的输出变量赋值 e = foo3; //endtask 语句>
任务调用为:
my_task(v,w,x,y,z);
任务调用变量(v,w,x,y,z)和任务定义的I/O变量(a,b,c,d,e)之间是一一对应的。当任务启动时,由v,w和x传入的变量赋给了a,b和c。当任务完成后的输出又通过c,d和e赋给x,y和z。
module traffic_lights; reg clock,red,amber,green; parameter on =1, off = 0, red_tics = 350,amber_tics = 30,green_tics = 200; initial red = off; initial amber = off; initial green = off;always @* //交通灯初始化 begin red = on; //开红灯 light(red,red_tics); //调用等待任务 green = on; //开绿灯 light(green,green_tics); //等待 amber = on; //开黄灯 light(amber,amber_tics); //等灯 endtask light(color,tics); //定义交通灯开启时间的任务 output color; input [31:0] tics; begin repeat(tics) @(posedge clock); //等待tics个时钟的上升沿 color = off; endendtaskalways begin //产生时钟脉冲的always块 #100 clock = 0; #100 clock = 1;endendmodule
三.函数(function)
函数的目的是返回一个用于表达式的值。
1.函数定义语法
function <返回值的类型或范围> (函数名) <端口说明语句> <变量类型说明语句> begin <语句> ... endendfunction 语句> 变量类型说明语句> 端口说明语句> 返回值的类型或范围>
注意:<返回值的类型或范围>这一项是可选项,如缺省则返回值为一位寄存器类型数据。例如:
function [7:0] getbyte; input [15:0] address; begin <说明语句> //从地址字节中提取低字节的程序 getbyte = result_expression; //把结果赋予函数的返回字节 endendfunction 说明语句>
2.函数返回值
函数的定义蕴含声明了与函数同名的、函数内部的寄存器。如在函数的声明语句中<返回值的类型或范围>为缺省,则这个寄存器是一位;否则是与函数定义中<返回值的类型或范围>一致的寄存器。
函数的定义把函数返回值赋值寄存器的名称初始化为与函数同名的内部变量。上面的例子说明这个概念:getbyte被赋予的值就是函数的返回值。
3.函数调用
函数的调用是通过将函数作为表达式中的操作数来实现的,其调用格式为:
<函数名> ( <表达式> <, <表达式> >*) 表达式> 表达式> 函数名>
其中函数名作为确认符。例如通过对两次调用函数getbyte的结果进行位拼接运算来生成一个字。
word = control?{getbyte(msbyte),getbyte(lsbyte)}:0;
4.函数使用规则
与任务相比函数的使用有较多的约束,规则为:
- 函数的定义不能包含有任何的时间控制语句,即任何用#、@或wait来标识的语句
- 函数不能启动任务
- 定义函数时至少要有一个输入参数
- 在函数的定义中必须有一条赋值语句给函数中的一个内部变量赋以函数的结果值,该内部变量具有和函数名相同的名字
5.实例详解
下面定义一个可进行阶乘运算的名为factorial函数,该函数返回一个32位的寄存器类型的值,该函数可后向调用自身,并且打印出部分结果值。
module tryfact; //模块开始//函数的定义------------------------------function [31:0] factorial; //函数开始 input [3:0] operand; //函数入口 reg [3:0] index; // 函数的寄存器 begin factorial = operand?1:0; //若operand全为0,则为0 for(index = 2; index <= operand; index = index +1) //循环语句 factorial = index * factorial; //乘法器 endendfunction //函数结束//函数的测试---------------------------------------------------------reg [31:0] result;reg [3:0] n;initial begin result = 1; for(n=2;n<=9;n=n+1) //循环语句(调用函数) begin $display("Partial result n= %d result= %d",n,result) //每次函数的执行结果 result = n*factorial(n)/((n*2)+1); //调用函数 end $display("Finalresult = %d",result); //打印结果 endendmodule //模块结束
注:
1.函数(function)
函数在一个仿真时间单位内执行完毕,因此不能包含任务、不能使用非阻塞赋值。使用上都是把函数作为表达式中的一个操作数。
2.任务(task)
任务可以包含时序控制语句,例如延迟语句,这样会造成该任务不可综合,在任务定义结构内不能出现initial和always过程块,但任务调用语句可以在initial语句和always语句中使用。也可以调用其它任务和函数;可以使用任意类型的参数,也可以没有参数。可综合任务只能实现组合逻辑,也就是说调用可综合任务的时间为“0”。而在面向仿真的任务中可以带有时序控制,如时延,因此面向仿真的任务的调用时间不为“0”。
不同点:
任务 task | 函数 function |
通常用于调试,或对硬件进行行为描述 | 通常用于计算,或描述组合逻辑 |
可以包含时序控制(#延迟,@, wait) | 不能包含任何延迟;函数仿真时间为0 |
可以有 input,output,和inout参数 | 只含有input参数并由函数名返回一个结果 |
可以调用其他任务或函数 | 可以调用其他函数,但不能调用任务 |
共同点:
1)任务和函数必须在module内调用
2)在任务和函数中不能声明wire
3)所有输入输出都是局部寄存器
4)任务函数执行完成后才返回结果
发表评论
最新留言
关于作者
