☰
SystemVerilog基础:disable fork语句
2026/10/26 1:15:02 网站建设 项目流程

相关阅读

SystemVerilog基础https://blog.csdn.net/weixin_45791458/category_12517449.html?spm=1001.2014.3001.5482https://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/134694526https://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.4450https://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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询