任务与函数


如果程序中有一段语句需要执行多次,则重复性的语句非常多,代码会变得冗长且难懂,维护难度也很大。任务和函数具备将重复性语句聚合起来的能力,类似于C语言的子程序。VerilogHDL中的task和function是可综合的,不过综合出来的都是组合电路。

一、        任务(task)语句

任务就是一段封装在“task……endtask”之间的程序。任务是通过调用来执行的,而且只有在调用时才执行,如果定义了任务,但是在整个过程中都没有调用它,那么这个任务是不会执行的。调用某个任务时可能需要它处理某些数据并返回操作结果,所以任务应当有接收数据的输入端和返回数据的输出端。另外,任务可以彼此调用,而且任务内还可以调用函数。

1.     任务定义

task定义的形式如下:

task task_id ;

      [declaration]

      prodedural_statement

endtask

其中,关键词task&endtask将它们之间的内容标志成一个任务定义,task标志着一个任务定义结构的开始;task_id是任务名;可选项declaration是端口声明语句和变量声明语句,任务接收输入值和返回输出值就是通过此处声明的端口进行的。prodedural_statement是一段用来完成这个任务操作的过程语句,如果过程语句多于一条,应将其放在语句块中;endtask为任务定义结构体结束标志。

注意事项:

Ø  在第一行“task”语句中不能列出端口名称;

Ø  任务的输入、输出端口和双向端口数量不受限制,甚至可以没有输入、输出及双向端口。

Ø  在任务定义的描述语句中,可以使用出现不可综合操作语句(使用最为频繁的就是延迟控制语句),但这样会造成该任务不可综合。

Ø  在任务中可以调用其它的任务和函数,也可以调用自身;

Ø  在任务定义结构内不能出现“initial & always”语句块;

Ø  在任务定义中可以出现“disable中止语句”,将中断正在执行的任务,但其是不可综合的。当任务被中断后,程序流程将返回到调用函数的地方继续向下执行。

2.     任务调用

虽然任务中不能出现initial语句和always语句,但任务调用语句可以在initial语句和always语句中使用,其语法形式如下:

 

       task_id[(端口1,端口2,……,端口N)] ;

 

       注意:任务调用语句中,参数列表的顺序必须与任务定义中的端口声明顺序相同。任务调用语句是过程性语句,所以任务调用中接收返回数据的变量必须是寄存器类型。

注意事项:

Ø  任

Ø  任务调用语句和一条普通的行为描述语句的处理方法一致;

Ø  当被调用输入、输出或双向端口时,任务调用语句必须包含端口名列表,且信号端口顺序和类型必须和任务定义结构中的顺序和类型一致。注意任务的输出端口必须和寄存器类型的数据变量对应。

Ø  可综合任务只能实现组合逻辑,也就是说调用可综合任务的时间为“0”。

例1:通过Verilog HDL的任务调用实现一个4比特全加器。

module add_4b_task(

    input [3:0] A,

    input [3:0] B,

    input CIN,

    output reg [3:0]S,

    output reg COUT

    );

        reg [1:0] S0,S1, S2, S3 ;

        // task语句

        task ADD;

                 inputA, B, CIN ;

                 outputreg [1:0] C ;

                 regS, COUT ;

                 begin

                         S= A ^ B ^ CIN ;

                         COUT= (A & B) | (A & CIN) | (B & CIN) ;

                         C= {COUT, S} ;

                 end

        endtask

 

        always @ (A orB or CIN)

                 begin

                         ADD(A[0],B[0], CIN, S0) ;

                         ADD(A[1],B[1], S0[1], S1) ;

                         ADD(A[2],B[2], S1[1], S2) ;

                         ADD(A[3],B[3], S2[1], S3) ;

                         S= {S3[0], S2[0], S1[0], S0[0]} ;

                         COUT= S3[1] ;

                 end

endmodule

二、        函数(function)语句

函数的功能和任务的功能类似,但两者存在很大的不同。在Verilog HDL语法中,也存在函数的定义和调用。

1       函数的定义

函数通过关键字function和endfunction定义,不允许输出端口声明(包括输出和双向端口),但可以有多个输入端口。函数定义的语法如下:

function [range] function_id;

       input_declaration ;

       other_declaration ;

       procedural_statement ;

endfunction

其中,function语句标志着函数定义结构的开始;[range]函数指定函数返回值的类型或位宽,是一个可选项,若没有指定,默认缺省值为1比特的寄存器数据;function_id为所定义函数的名称,对函数的调用也是通过函数名来完成的,并在函数结构体内部代表一个内部变量,函数调用的返回值通过函数名变量传递给调用语句;input_delaration用于对函数各个输入端口的位宽和类型进行说明,在函数定义中至少要有一个输入端口;endfunction为函数结构体结束标志。

函数定义实例如下:

function AND ;   //定义输入变量

        input A, B;       //定义函数体

        begin

                 AND= A && B ;

        end

endfunction

函数定义在函数内部会隐式定义一个寄存器变量,该寄存器变量和函数同名并且位宽也一致。函数通过在函数定义中对该寄存器的显式赋值来返回函数计算结果。此外,还要注意以下几点:

²  函数定义只能在模块中完成,不能出现在过程块中;

²  函数至少要有一个输入端口;不能包含输出端口和双向端口;

²  在函数结构中,不能使用任何形式的时间控制语句,也不能使用disable中止语句;

²  函数定义结构体中不能出现过程块语句(always语句);

²  函数内部可以调用函数,但不能调用任务。

2       函数的调用

调用函数的语句形式如下:

Func_id(expr1, expr2,……,exprN) ;

       其中,func_id是要调用的函数名,expr1,expr2,……,exprN是传递给函数的输入参数列表,该输入参数列表的顺序必须与函数定义时声明其输入的顺序相同。

       注意事项:

Ø  函数调用可以在过程块中完成,也可以在assign这样的连续赋值语句中出现;

Ø  函数调用语句不能单独作为一条语句出现,只能作为赋值语句的右端操作数。

 

例2:通过Verilog HDL的函数调用实现一个4比特全加器。

module add_4b_function(

    input [3:0] A,

    input [3:0] B,

    input CIN,

    output [3:0] S,

    output COUT

    );

        wire[1:0]  S0, S1, S2, S3 ;

        functionsigned [1:0] ADD;

                 inputA, B, CIN ;

                 regS, COUT ;

                 begin

                         S= A ^ B ^ CIN ;

                         COUT= (A & B) | (A & CIN) | (B & CIN) ;

                         ADD= {COUT, S} ;                      

                 end

        endfunction

 

        assign S0 =ADD(A[0], B[0], CIN) ;

        assign S1 =ADD(A[1], B[1], S0[1]);

        assign S2 =ADD(A[2], B[2], S1[1]);

        assign S3 =ADD(A[3], B[3], S2[1]);

        assign S ={S3[0], S2[0], S1[0], S0[0]} ;

        assign COUT =S3[1];

endmodule

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值