原创 task 和 functionM<转载>

2012-5-23 11:00 1367 14 14 分类: FPGA/CPLD

 

转载于:http://www.cnblogs.com/icelyb24/archive/2011/05/04/2036379.html

 

task 和 function
task和function说明语句分别用来定义任务和函数。
--特点
1、利用任务和函数可以把一个很大的程序模块分解成许多小的任务和函数便于理解和调用。
2、输入、输出和总线信号的值可以传入、传出任务和函数。
3、任务和函数往往还是打的程序模块中在不同地点多次用到的相同的程序段。
4、学会使用task和function语句可以简化程序的结构,使程序明白易懂,是编写较大型模块的基本功。
--task和function区别
task和function的主要不同有以下四点:
1、function只能与主模块公用一个仿真时间单位,而task可以定义自己的仿真时间单位。
2、function不能启动task,而task可以启动其他的task和function。
3、function至少有一个输入变量,而task可以没有或者有多个任何类型的变量。
4、function返回一个值,而task则不返回值。
--目的
function的目的是通过返回一个值来响应输入信号的值。
task能支持多种目的,能计算多个结果值,这些结果值之恩能通过被调用的task的输出或者总线端口送出。
--举例
Verilog中模块使用函数时是把它当作表达式中的操作符,这个操作的结果就是这个函数的返回值。例如:

定义一个task或者function对一个16位的字进行操作,让高字节与低字节互换,把它变为另一个字(假定这个任务或函数名为:switch_bytes)。

task返回的新字是通过输出端口的变量,因此16位字字节互换任务的调用源码是这样的:
  switch_bytes(old_word,new_word);
任务switch_bytes把输入old_word的字的高低字节互换放入new_word端口输出。

function返回的新字是通过函数本身的返回值,因此16位字字节互换函数的调用源码是这样的:
  new_word = switch_butes(old_word);
函数switch_bytes把输入的old_word的字的高低字节互换后赋值给new_word。

--task说明
如果传给任务的变量值和任务完成后接收结果的变量已定义,就可以用一条语句启动任务。任务完成以后控制就传回启动过程。如果任务内部有定时控制,则启动的时间可以与控制返回的时间不同。任务可以启动其他的任务。其他的任务又可以启动别的任务,可以启动任务数是没有限制的。不管有多少任务启动,只有当所有的启动任务完成以后,控制才能返回。

1、任务的定义
定义任务语法如下:
------------------------------------------------------
---------------
任务:
 task <任务名>;
  <端口及数据类型声明语句>;
  <语句1>;
  <语句2>;
  <语句3>;
  ...
  <语句n>;
 endtask
这些声明语句的语法与模块定于中的对应声明语句语法一致。
2、任务的调用及变量的传递
启动任务并传递输入输出变量的声明语句的语法如下:
任务的调用:
 <任务名> (端口1,端口2,端口3,...,端口n);
下面举例说明:
任务定义:

task my_task;
  input a;
  input b;
  inout c;
  output d;
  output e;
  ...
  <语句>  //执行任务工作响应的语句
  ...
  c = fool1; //赋初始值
  d = fool2; //对任务的输出变量赋值;
  e = fool3; 
 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;
 reg red;
 reg amber;
 reg 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); //等待
end
//定义交通灯开启时间的任务
task light(color,tics);
 output color;
 input[31:0] tics;

 begin
  repeat(tics) @(posedge clock);//等待tics个时钟的上升沿
  color=off;//关灯
 end
endtask
//产生时钟脉冲的always块
always begin
 #100 clock=0;
 #100 clock=1;
end

endmodule



这个例子描述了一个简单的交通灯的时序控制,并且该交通灯有它自己的时钟产生器。

--function说明
函数的目的是返回一个用于表达式的值。

1、定义函数的语法:

 
function <返回值的类型和范围>(函数名);
  <端口说明语句>;
   begin 
    <语句>
    ........
   end
 endfunction

请注意<返回值的类型或范围>这一项是可选的,如果缺省则返回值为一位寄存器类型的数据。下面举例说明:

function [7:0] getbyte;
 input [15:0] address;
 begin
  <说明语句> //从地址字中提取低字节的程序
  getbyte = result_expression;
 end
endfunction

2、从函数返回的值
函数的定义蕴含声明了与函数同名的、函数内部的寄存器。入在函数的声明语句中<返回值的类型或范围>为缺省,则这个寄存器是一位的,否则是与函数定义中<返回值的类型或范围>一致的寄存器。函数的定义把函数返回值所赋值寄存器的名称初始化为函数同名的内部变量。下面的例子说明了这个概念:getbyte被赋予的值就是函数的返回值。
3、函数的调用
函数的调用是通过将函数作为表达式中的操作数来实现的。
其调用格式如下:
 <函数名> (<表达式><,<表达式>>*)
其中函数名作为确认符。下面的例子通过对两次调用函数getbyte的结果值进行位拼接运算来生成一个字。
 word = control ? {getbyte(msbyte),getbyte(lsbyte)} : 0;
4、函数的使用规则
与任务相比函数的使用有较多的约束,下面给出的是函数的使用规则:
a、函数的定义不能包含有任何的时间控制语句,即任何使用#、@或wait来标识的语句。
b、函数不能启动任务。
c、定义函数时至少要有一个输入参量。
d、在函数的定义中必须有一条赋值语句给函数中的一个内部变量赋以函数的结果值,该内部变量具有和函数相同的名字。

举例说明如下:
例子中定义了一个可进行阶乘预算的名为factiorial的函数,该函数返回了一个32位的寄存器类型的值,该函数可后向调用自身,并且打印出部分结果值。

 

module tryfact;
 //函数定义------------------------------
function [31:0] operand;
 input [3:0] operand;
 reg [3:0] index;
 begin
  factorial = operand ? 1 : 0;
  for(index = 2; index <= operand; index = index + 1)
  factorial = index * factorial;
 end
endfunction
//函数的测试----------------------------------
 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);
end
endmodule//模块结束

 

文章评论0条评论)

登录后参与讨论
我要评论
0
14
关闭 站长推荐上一条 /2 下一条