4. SystemVerilog Task
## SV中的task
- SystemVerilog中的task同Verilog的task语法及使用相同,数据类型稍有区别
- 任务是一段可重用的代码,用于执行特定的操作。
- 与函数不同,任务可以包含时序控制语句(如
#
延迟或@
触发事件)。 - 任务可以有输入、输出和
inout
类型的参数。
任务的基本语法
语法1
task [name];
input [port_list];
inout [port_list];
output [port_list];
begin
[statements]
end
endtask
语法2
task [name] (input [port_list], inout [port_list], output [port_list]);
begin
[statements]
end
endtask
空端口列表
task [name] ();
begin
[statements]
end
endtask
静态任务
- 如果任务是静态的,则其所有成员变量将在不同的并发调用之间共享。
- 使用
static
关键字声明静态任务。
Example:
module tb;
initial display();
initial display();
initial display();
initial display();
// 这是一个静态任务
task display();
integer i = 0;
i = i + 1;
$display("i=%0d", i);
endtask
endmodule
- 输出:
i=1 i=2 i=3 i=4
自动任务
- 使用
automatic
关键字声明自动任务。 - 自动任务在每次调用时都会动态分配内存,不共享数据。
Example:
module tb;
initial display();
initial display();
initial display();
initial display();
// 注意任务现在是自动的
task automatic display();
integer i = 0;
i = i + 1;
$display("i=%0d", i);
endtask
endmodule
- 输出:
i=1 i=1 i=1 i=1
全局任务
- 在所有模块外部声明的任务称为全局任务,具有全局作用域,可以在任何模块中调用。
Example:
// 这个任务在所有模块之外
task display();
$display("Hello World!");
endtask
module des;
initial begin
display();
end
endmodule
- 输出:
Hello World!
如果任务是在模块内部声明的,则必须通过模块实例名来调用。
Example:
module tb;
des u0();
initial begin
u0.display(); // 任务在模块 'tb' 中不可见
end
endmodule
module des;
initial begin
display(); // 任务定义在模块内
end
task display();
$display("Hello World");
endtask
endmodule
- 输出:
Hello World Hello World
函数与任务的区别
特性 | 函数 | 任务 |
---|---|---|
时序控制 | 不能有时间控制语句/延迟 | 可以包含时间控制语句/延迟 |
任务启用 | 不能启用任务 | 可以启用其他任务和函数 |
参数类型 | 至少有一个输入参数,不能有输出或 inout 参数 |
可以有零个或多个任意类型的参数 |
返回值 | 只能返回一个值 | 不能返回值,但可以通过输出参数实现相同效果 |
Example:
module tb;
reg signal;
initial wait_for_1(signal);
function wait_for_1(reg signal);
#10; // 编译器会报错
endfunction
endmodule
- 错误信息:
illegal time/event control statement within a function or final block or analog initial block [10.3.4(IEEE)].
禁用任务
- 使用
disable
关键字可以禁用任务。
Example:
module tb;
initial display();
initial begin
// 50 个时间单位后,禁用任务 'display' 中名为 T_DISPLAY 的块
#50 disable display.T_DISPLAY;
end
task display();
begin : T_DISPLAY
$display("[%0t] T_Task started", $time);
#100;
$display("[%0t] T_Task ended", $time);
end
begin : S_DISPLAY
#10;
$display("[%0t] S_Task started", $time);
#20;
$display("[%0t] S_Task ended", $time);
end
endtask
endmodule
- 输出:
[0] T_Task started [60] S_Task started [80] S_Task ended