相关阅读
SystemVerilog基础https://blog.csdn.net/weixin_45791458/category_12517449.html?spm=1001.2014.3001.5482
一、进程的概念
在学习disable fork语句之前,首先的了解SystemVerilog中的进程概念:进程是一系列可以独立执行的一个或多个表达式。
SystemVerilog中每个initial语句、always语句(包括always、always_comb、always_latch和always_ff)、final语句和连续赋值语句都定义了一个独立的静态进程,它们的存在由静态层次结构决定,并从仿真开始时开始,并且它们无法在运行时创建。
除此之外SystemVerilog还有动态进程,这些进程可以在运行时创建、停止、重新启动和销毁。
二、子进程的概念
上一小节中定义了进程的概念并说明了创建进程的语句有哪些,但是这些进程是独立且不可嵌套的,也就是说所有的initial语句、always语句、final语句和连续赋值语句在一个模块中都是并列的顶层进程。
fork语句(包括fork-join、fork-join_any、fork-join_none)可以动态创建子进程,其中每条并行的语句都是独立的子进程,当执行到fork语句时子进程创建。
关于这三种fork语句的区别,请参考下面的博客。
SystemVerilog基础:并行块fork-join、join_any、join_none(上)https://chenzhang.blog.csdn.net/article/details/134694526
三、测试
在学习了进程和子进程的概念后,下面通过几个例子来巩固知识。
问题1:例1中存在几个顶层进程?
// 例1
module example1;
// 信号声明
reg clk, reset;
reg [7:0] data_in, data_out;
reg [3:0] address;
wire [7:0] result;
// 连续赋值语句
assign result = data_in + data_out;
// initial 语句
initial begin
$display("Simulation started");
clk = 0;
reset = 1;
data_in = 8'h00;
data_out = 8'h00;
address = 4'b0000;
#10 reset = 0;
end
// always 语句
always begin
#5 clk = ~clk; // 产生时钟信号
end
// always_comb 语句
always_comb begin
if (reset) begin
data_out = 8'h00;
end else begin
data_out = data_in + 1;
end
end
// always_latch 语句
always_latch begin
if (reset) begin
address = 4'b0000;
end else begin
address = address + 1;
end
end
// always_ff 语句
always_ff @(posedge clk or posedge reset) begin
if (reset) begin
data_in <= 8'h00;
end else begin
data_in <= data_in + 1;
end
end
// final 语句
final begin
$display("Simulation finished");
end
// function 定义
function [7:0] add_two_numbers;
input [7:0] a, b;
begin
add_two_numbers = a + b;
end
endfunction
// task 定义
task print_address;
input [3:0] addr;
begin
$display("Current address: %b", addr);
end
endtask
// 调用function和task
initial begin
#20;
$display("Sum: %h", add_two_numbers(8'h10, 8'h20)); // 调用function
print_address(4'b1010); // 调用task
end
endmodule
答案1:存在八个顶层进程(需要注意的是,task和function并不属于顶层进程的一种)。
问题2:例2中存在几个子进程?
// 例2
module example2;
// 信号声明
reg clk, reset;
reg [7:0] data_in, data_out;
// initial 语句
initial begin // begin-end语句
$display("Simulation started");
fork // fork-join 语句
data_in = 8'hAA;
begin // begin-end语句
#10 data_in = 8'hBB;
#10 data_in = 8'hCC;
end
join
data_out = data_in + 1;
$display("Data out: %h", data_out);
end
endmodule
答案2:存在两个子进程,分别是fork-join语句中的data_in = 8'hAA;语句和begin-end语句。其中begin-end语句作为子进程,又由两条阻塞赋值语句组成。顶层进程initial中只有一条begin-end语句,而其中又有四条语句(两条$display语句、一条阻塞赋值语句和一条fork-join语句)。
四、disable fork语句
disable fork语句终止该语句所在进程创建的所有活跃的子进程,其语法如下所示:
disable fork;
disable fork语句不仅终止该语句所在进程创建的所有活跃的子进程,还终止子进程的子进程。换句话说,如果任何子进程有自己的子进程,禁用fork语句也将终止它们(这类似disable语句)。
下面是来自SystemVerilog标准的例子。
task get_first( output int adr );
fork
wait_device( 1, adr );
wait_device( 7, adr );
wait_device( 13, adr );
join_any
disable fork;
endtask
在任务get_first中,fork-join_any语句创建了三个子进程,每个子进程等待特定设备(1、7、13)就绪并返回其地址。当三个子进程中有任意一个完成时,继续执行父进程中的disable fork语句并终止剩下的两个子进程。
下面的例3进一步说明了,调用task并不创建子进程。
// 例3
module example3;
// 信号声明
reg clk, reset;
reg [7:0] data_in, data_out;
task disable_task;
begin
disable fork;
end
endtask
task fork_task;
begin
fork
$display("Task start");
#10 $display("Task stop"); // 该语句永远不会执行
join_none
end
endtask
// initial 语句
initial begin
fork_task;
#5 disable_task;
end
endmodule
在例3中,只有在执行fork-join_none语句时创建了两个子进程,而其他语句都属于顶层进程initial,因此任务disable_task中的disable fork语句终止了另一个任务中的#10 $display("Task stop");语句,因为该语句在执行disable fork语句时是顶层进程的活跃子进程(子进程$display("Task start");语句此时已经结束了)。
问题3:假设将例3中的initial语句中的begin-end语句换成fork-join语句,如例4所示,此时还能与之前有同样的效果吗?
// 例4
module example4;
// 信号声明
reg clk, reset;
reg [7:0] data_in, data_out;
task disable_task;
begin
disable fork;
end
endtask
task fork_task;
begin
fork
$display("Task start");
#10 $display("Task stop"); // 该语句会执行
join_none
end
endtask
// initial 语句
initial fork
fork_task;
#5 disable_task;
join
endmodule
答案4:不行,因为此时disable fork语句所在的进程已经不是任务fork_task中语句的父进程了,事实上disable fork语句所在的进程只有一条disable-fork语句。
五、写在最后
当disable fork语句终止进程执行时,会有一些其他的副作用,本文将不对此进行详述,具体可参考下面的博客(除其中第三点外)。
Verilog基础:disable语句https://blog.csdn.net/weixin_45791458/article/details/131543670?ops_request_misc=%257B%2522request%255Fid%2522%253A%25220317350431fbd1bf31f233a546d22a2e%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=0317350431fbd1bf31f233a546d22a2e&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-131543670-null-null.nonecase&utm_term=disable&spm=1018.2226.3001.4450