三、9【Verilog HDL】任务和函数

本文详细讲解了Verilog中任务和函数的区别,任务适用于包含延迟、时序和事件的模块,而函数专用于纯组合逻辑。介绍了任务的声明、调用及自动任务的概念,同时也阐述了函数的声明、调用,包括组合逻辑函数、自动递归函数和常量函数的应用。
摘要由CSDN通过智能技术生成

前言 

参考书籍:《Verilog HDL 数字设计与综合》第二版,本文档为第8章的学习笔记。

在行为级建模时很多不同的地方会实现相同的功能,有必要将相同部分取出来,将其组成子程序,然后其他地方调用。Verilog也提供了任务和函数可以将较大的行为级设计划分为较小的代码段,允许多个地方使用。

任务和函数也可以通过层次名进行引用。

学习目标

  • 理解任务和函数区别
  • 定义任务和函数所需条件,任务和函数的声明和调用

8.1 任务和函数的区别

任务和函数必须在模块内部进行定义,其作用范围仅局限于定义他们的模块。

任务用于代替普通Verilog代码,可包括延迟、时序、事件等语法结构,且可有多个输出变量;

函数用于表示纯组合逻辑Verilog代码,在仿真时刻0开始执行,只能有一个输出,因此一般完成各类转换和常用的计算。

任务和函数中声明局部变量(寄存器、时间、整数、实数和事件),但不能声明线网型变量。只能使用行为级语句,但是不能包含always和initial块。但是在always和initial块以及其他任务和函数中调用任务和函数。

8.2 任务

任务关键字:taskendtask进行声明。如果子程序满足下面任意一个条件,则必须使用任务而不能使用函数:

  • 子程序中包含有延迟、时序或者事件控制结构(函数多用于组合逻辑)。
  • 没有输出或者输出变量的数目大于1(函数只能有一个输出)。
  • 没有输入变量

8.2.1 任务的声明和调用

 可以使用input、output、inout来规定的任务的输入输出变量。

任务可在模块、其他任务或函数中调用。

8.2.2 任务举例

1、输入和输出变量的使用

//在模块中调用任务实例
module op();
...
...
parameter delay = 10;
reg [15:0] A, B;
reg [15:0] AB_AND, AB_OR, AB_XOR;
always @(A or B)
begin
    oper(AB_AND, AB_OR, AB_XOR, A, B);
end
...
...
//定义任务
task oper;
output [15:0] ab_and, ab_or, ab_xor;
input [15:0] a, b;
begin
    #delay ab_and = a & b;
    ab_or = a | b;
    ab_xor = a ^ b;
end
endtask
...
endmoudle
//ANSI C风格编程
task oper(output [15:0] ab_and, ab_or, ab_xor,
    input [15:0] a, b
    );
begin
    #delay ab_and = a & b;
    ab_or = a | b;
    ab_xor = a ^ b;
end
endtask
    

2、非对称序列发生器

module sequence
...
reg clock;
...
initial
    init_sequence;     //启动init_sequence任务
...
always
begin
    asy_sequence;      
end
...
...
task init_sequence;
begin
    clock = 1'b0;
end
endtask

//时钟操作
task asy_sequence;
begin
    #20 clock = 1'b1;
    #20 clock = 1'b0;
end
endtask
...
endmodule

8.2.3 自动(可重入)任务

任务本身上是静态的,任务中所有声明项的地址空间是静态分配的,同时并发执行的多个任务共享这些存储区。因此,如果任务在同一模块中两个地方被同时调用,则这两个任务调用将对同一地址空间操作,因此有可能出现错误。

为避免上述问题,在task关键字前面添加automatic关键字,使任务成为可重入的,这样声明的任务称为自动任务。这样在每次调用任务时,存储空间是动态分配的,每个调用都对各自独立的地址空间进行操作。

//在模块中调用任务实例
module op();
...
...
parameter delay = 10;
reg [15:0] A, B;
reg [15:0] AB_AND, AB_OR, AB_XOR;
always @(A)
begin
    oper(AB_AND, AB_OR, AB_XOR, A, B);
end
always @(B)
begin
    oper(AB_AND, AB_OR, AB_XOR, A, B);
end
...
...
//定义任务
task automatic oper;
output [15:0] ab_and, ab_or, ab_xor;
input [15:0] a, b;
begin
    #delay ab_and = a & b;
    ab_or = a | b;
    ab_xor = a ^ b;
end
endtask
...
endmoudle

8.3 函数

函数关键字:fuctionendfuction进行声明。如果子程序满足下面条件全部成立,则可以使用函数来完成:

  • 子程序中不包含有延迟、时序或者事件控制结构(由于从0开始执行)。
  • 子程序只有一个返回值。
  • 至少有一个输入变量。
  • 没有输出或者双向变量
  • 不含有非阻塞赋值语句

函数中多为组合逻辑表达

8.3.1 函数的声明和调用

函数具有的特点:

当函数声明时,在Verilog的内部隐含地声明了一个名为function_identifier(函数标识符)的寄存器类型变量,函数的输出结果通过这个寄存器类型变量被传回。可选项rang_or_type(类型或范围)说明了内部寄存器的位宽。如果没有指定返回值的类型或位宽,则默认位宽为1。

由于函数自带function_identifier,包含了函数返回值,因此函数时没有输出变量的。另外函数中不能调用任务,只能调用其他函数。

8.3.2 函数举例

 1、奇偶检验位的计算

//定义一个包含奇偶校验函数的模块
module par;
...
reg [31:0] addr;
reg parity;
always @(addr)
begin
    parity = calc_parity(add);
    $display("calc_parity = %b", calc_parity(add));
end
...
function calc_parity(input [31:0] address);
    begin
        calc_parity = ^address;           //返回所有地址位的异或值
    end
endfunction
...
endmodule

2、左、右移位寄存器

//定义一个含有移位函数的模块
module shifter;
...
`define LEFT  1'b0
`define RIGHT 1'b1
reg [31:0] addr, left_addr, right_addr;
reg control;
always @(addr)
begin

end
...
function [31:0] shift(
    input [31:0] address,
    input control
    ); 
begin
    shift = (control == `LEFT) ? (address<<1) : (address>>1);
end
endfunction
...
endmoudle

8.3.3 自动(递归)函数

函数是不可以递归调用的,在一个模块中不能两次调用,调用时使用同一地址,导致结果不确定。

因此使用关键字automatic,可动态分配地址。但是自动函数中的局部变量不可以通过层次名进行访问,但是函数名可以。

function automatic integer factorial;              //与任务类似这里不再进行代码举例

8.3.4 常量函数

实际上是一个带有某些限制的常规函数。能用来引用复杂的值,因此可以用来代替常量。

//定义一个RAM类型
module ram();
parameter RAM_DEPTH 256;
input [clogb2(RAM_DEPTH) - 1 : 0] addr_bus;
//通过函数得到clogb2(RAM_DEPTH)=8
//常量函数
fucntion integer clogb2(input integer depth);    //integer:声明整数寄存器类型 
begin
    for(clogb2=0; depth>0; clogb2=clogb2+1)
        depth = depth >> 1;
end
endfuntion
...
endmodule

8.3.5 带符号函数

module top;
function signed [63:0] compute_signed(input [63:0] vector);
...
endfunction
if(compute_signed(vector) < -3)
...
endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追逐者-桥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值