1. 任务与函数的区别
和函数(function)一样,任务(task)可以用来描述共同的代码段,并在模块内任意位置被调用。
函数一般用于组合逻辑
的各种转换和计算;而任务更像一个过程,不仅能完成函数的功能,还可以包含时序控制逻辑。
任务与函数的区别:
比较点 | 函数 | 任务 |
---|---|---|
输入 | 函数至少有一个输入,端口不能包含 inout 型 | 任务可以没有或者多个输入,且端口声明可以为 inout 型 |
输出 | 函数没有输出 | 任务可以没有或者多个输出 |
返回值 | 函数至少有一个返回值 | 任务没有返回值 |
仿真时刻 | 函数总在零时刻就开始执行 | 任务可以在非零时刻执行 |
时序逻辑 | 函数不能包含任何时序控制逻辑 | 任务不能出现 always 语句,但可以包含其它时序控制,如延时语句 |
调用 | 函数只能调用函数,不能调用任务 | 任务可以调用函数与任务 |
书写规范 | 函数不能单独作为一条语句出现,只能放在赋值语句的右端 | 任务可以作为一条语句出现在语句块中 |
2. 任务
2.1 任务声明
任务在模块中任意位置定义,并在模块内任意位置引用,作用范围也局限于此模块。
格式如下
verilog
task task_id ;
port_declaration ;
procedural_statement ;
endtask
task <任务名字> ;
<端口声明> ;
<操作语句> ;
endtask
任务中使用 input,output,inout 对端口进行声明。
input,inout 型端口将变量从任务外部传递到内部,output,inout 型端口将任务执行完后的结果传回内部。
示例如下
verilog
task add ;
input wire a ;
input wire b ;
output reg c ;
#3 c = a & b ;
endtask
2.2 任务调用
任务可单独作为一条语句出现在 initial,always 块中。
格式如下
verilog
task_id( input1, input2, ... output1, output2, ... ) ;
任务调用时,端口必须按顺序对应。
输入端连接的模块内信号可以时 wire,reg 型。
输出端连接的模块内信号一定是 reg 型。
示例如下
verilog
module test(
input wire clk_i ,
input wire rst_n_i ,
input wire [7:0] a_i ,
input wire [7:0] b_i ,
output reg [7:0] c_i
);
reg [7:0] c_r ;
always @(*) begin
x( a, b, c_r ) ; /// 函数调用
end
reg [7:0] c_r1 ;
always @( posedge clk_i or rst_n_i ) begin
if( !rst_n_i ) begin
c_r1 <= 0 ;
end
else begin
c_r1 <= c_r ;
end
end
always @( posedge clk_i or negedge rst_n_i ) begin
if (!rst_n_i ) begin
c_i <= 0 ;
end
else begin
c_i <= c_r1 ;
end
end
/// 函数
task x ;
input wire [7:0] numa ;
input wire [7:0] numb ;
output reg [7:0] numc ;
#10 numc = numa ^ numb ;
endtask
endmodule
3. 任务操作全局变量
因为任务可以看作过程性赋值,所以任务的 output 端信号返回时间是在任务中所有语句执行完毕之后。
示例如下
verilog
/// example1
task clk1 ;
output clk ;
#5 ; clk = 0 ;
#5 ; clk = 1 ;
endtask
reg clk1_r ;
always clk1( clk1r ) ;
/// example2
reg clk2_r ;
task clk2 ;
#5 ; clk2_r = 0 ;
#5 ; clk2_r = 1 ;
endtask
always clk2 ;
-
第 1 种描述方式
虽然任务内部有赋值 0 和赋值 1 的操作,但是中间变化的过程并不可见。
最后输出的结果只能是任务内所有语句执行完毕后输出端信号的最终值。
所以信号 clk 1 的值恒为 1。这种方式产生不了时钟。
-
第 2 种描述方式
虽然没有端口信号,但是直接对
全局变量
进行过程赋值,因此该全局变量对模块是可见的。因此任务内该信号翻转过程会在信号 clk 2 中体现出来。这种方式会产生一个 10 个时间单位的周期的时钟。
【图床问题,仿真图待补充】
4. automatic 任务
和函数一样,verilog 中任务调用时的局部变量都是静态的。
可以用关键字 automatic 来对任务进行声明,那么任务调用时个存储空间就可以动态分配。
每个调用的任务都各自独立的对自己独有的地址空间进行操作,而不影响多个相同任务调用时的并发执行。
如果一个任务代码段被2处及以上调用,一定要用关键字automatic声明。
当没有使用 automatic 声明任务时,任务被 2 次调用,可能出现信号间干扰。
【工程待补充】