SystemVerilog基础:并行块fork-join、join_any、join_none(二)

相关阅读

SystemVerilog基础icon-default.png?t=N7T8https://blog.csdn.net/weixin_45791458/category_12517449.html


        在第一节中,我们讨论了并行块中的fork-join块和fork-join_any块,了解了它们的差异,本文将继续讨论fork-join_none块的使用。

        fork-join_none并行块拥有和普通的fork_join并行块一样的语句并行性质,即块内的语句在同一仿真时间执行,但它拥有一个特性,即完全不阻碍父线程的执行,下面是SystemVerilog标准中的解释。

         大意为fork-join_none并不会阻碍父线程的执行,也就是说父线程可以接着执行其他的语句,但标准仍然提供了一定的确定性,如上面的最后一句所说,fork-join_none块的语句不会执行,直到父进程遇到了一个阻塞语句或调度结束。

        上面的阻塞语句如何解释呢?是否是指阻塞赋值<=吗?其实不是的,这里的阻塞语句其实是指有过程语句前置时序控制的语句,即语句前有#,@或wait。在这里我们不讨论过程语句前置时序控制相关内容,它可以在以往的文章中找到(需要特别注意的是,这里的时序控制包括#0)。Verilog基础:延时模型_verilog延时模块-CSDN博客文章浏览阅读501次,点赞13次,收藏34次。Verilog基础专栏。_verilog延时模块https://blog.csdn.net/weixin_45791458/article/details/132579787?spm=1001.2014.3001.5502        下面我们来看几个例子,加深对fork-join_none块的理解。

例1
`timescale 1ns/1ns 
module test();
initial begin
    $display("Out of fork join_none1");
    $display("Out of fork join_none2");
    fork
        $display("In fork join_none1");
        $display("In fork join_none2");
    join_none
    $display("Out of fork join_none3");
    $display("Out of fork join_none4");
end
endmodule

输出:
Out of fork join_none1
Out of fork join_none2
Out of fork join_none3
Out of fork join_none4
In fork join_none1
In fork join_none2

        例1的结果显示,fork-join_none并行块内的语句在最后才执行,因为当控制流执行到fork-join_none并行块时,会跳过fork-join_none并行块而查看后面的语句,直到遇到一个阻塞语句或begin-end块的结尾(调度结束),在例1中是指begin-end块的结尾(调度结束),才会去执行fork-join_none并行块内的语句。

        下面的例2展示了另一种情况,即遇到一个阻塞语句。

例2
`timescale 1ns/1ns 
module test();
initial begin
    $display("Out of fork join_none1");
    $display("Out of fork join_none2");
    fork
        $display("In fork join_none1");
        $display("In fork join_none2");
    join_none
    $display("Out of fork join_none3");
    #1 $display("Out of fork join_none4");
end
endmodule

输出:
Out of fork join_none1
Out of fork join_none2
Out of fork join_none3
In fork join_none1
In fork join_none2
Out of fork join_none4

        当控制流执行到#1 $display("Out of fork join_none4");这个阻塞语句时,控制流会转去执行fork-join_none并行块内的语句。所以结果显示fork-join_none并行块内的语句在0ns仿真时间最后才被执行。

        现在出现了一个问题,当fork-join_none并行块的父线程是fork-join时,会出现什么情况?下面来看一个这样的例子。

例3
`timescale 1ns/1ns 
module test();
initial fork
    $display("Out of fork join_none1");
    $display("Out of fork join_none2");
    fork
        $display("In fork join_none1");
        $display("In fork join_none2");
    join_none
    $display("Out of fork join_none3");
    #1 $display("Out of fork join_none4");
join
endmodule

         为什么例3没有直接给出输出呢,因为它并没有一个确定的输出,fork-join块内语句的执行顺序是不定的,所以可能有多种情况发生。

1、如果fork-join_none并行块在#1 $display("Out of fork join_none4");后被调度,fork-join_none并行块内语句只有等到fork-end块调度结束时才会执行,体现的输出为

Out of fork join_none1 //前三个输出顺序是不定的
Out of fork join_none2
Out of fork join_none3
In fork join_none1     //这两个输出顺序是不定的
In fork join_none2    
Out of fork join_none4 //这个输出一定在最后(但它在fork-join_none并行块前调度)

2、如果fork-join_none并行块在#1 $display("Out of fork join_none4");前被调度,fork-join_none并行块内语句在等到#1 $display("Out of fork join_none4");被调度时就会执行,体现的输出为

Out of fork join_none1 //这五个个输出的顺序是不定的
Out of fork join_none2
Out of fork join_none3
In fork join_none1     
In fork join_none2    
Out of fork join_none4 //这个输出一定在最后(但它在fork-join_none并行块后调度)

       下面给出了几款常见的仿真器的输出结果。

对于Mentor Modelsim SE,输出结果为
Out of fork join_none1
Out of fork join_none2
In fork join_none1
In fork join_none2
Out of fork join_none3
Out of fork join_none4
 
对于Aldec Riviera Pro,输出结果为
Out of fork join_none1
Out of fork join_none2
In fork join_none1
In fork join_none2
Out of fork join_none3
Out of fork join_none4
 
对于Cadence Xcelium,输出结果为
Out of fork join_none1
Out of fork join_none2
In fork join_none1
In fork join_none2
Out of fork join_none3
Out of fork join_none4
 
对于Mentor Questa,输出结果为
Out of fork join_none1
Out of fork join_none2
In fork join_none1
In fork join_none2
Out of fork join_none3
Out of fork join_none4
 
对于Synopsys VCS,输出结果为
Out of fork join_none1
Out of fork join_none2
Out of fork join_none3
In fork join_none1
In fork join_none2
Out of fork join_none4

        从输出结果可以看出,Synopsys VCS似乎采取了情况1的处理方式,而其他仿真器使用了情况2的处理方式。这告诫了我们,不要写出这种令人费解的有不确定性的代码。

        下面展示了一个稍微复杂一些的例子作为题目,如果你看懂了上面的内容,你应该能预测它的输出。

例4
`timescale 1ns/1ns 
module test();
initial begin
    for (int j=0; j<3; j++) begin 
        fork
            $display(j);
        join_none
    end
end
endmodule

        因为fork-join_none并行块需要等待父线程的调度结束后才执行,因此并不会在迭代时直接显示输出,而是等待for循环结束遇到begin-end块的结尾(调度结束)。

        输出结果为三个3。

相关推荐

  1. SystemVerilog基本语法和流水的实现

    2023-12-17 04:50:03       29 阅读
  2. SystemVerilog Constants、Processes

    2023-12-17 04:50:03       42 阅读
  3. SystemVerilog测试框架示例

    2023-12-17 04:50:03       26 阅读
  4. systemverilog的关联数组

    2023-12-17 04:50:03       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-17 04:50:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-17 04:50:03       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-17 04:50:03       82 阅读
  4. Python语言-面向对象

    2023-12-17 04:50:03       91 阅读

热门阅读

  1. Python简介、开发环境配置与工具准备

    2023-12-17 04:50:03       58 阅读
  2. 《C++新经典设计模式》之第1章 介绍

    2023-12-17 04:50:03       34 阅读
  3. 什么是npm?

    2023-12-17 04:50:03       55 阅读
  4. leetcode - 1665. Minimum Initial Energy to Finish Tasks

    2023-12-17 04:50:03       52 阅读
  5. 免杀-一句话的免杀

    2023-12-17 04:50:03       62 阅读
  6. android 检测u盘和sdcard

    2023-12-17 04:50:03       50 阅读
  7. 按位与例题

    2023-12-17 04:50:03       60 阅读
  8. 前段js解决文本框录入保留多位小数设置

    2023-12-17 04:50:03       42 阅读
  9. 重构第五章:重构的方法

    2023-12-17 04:50:03       47 阅读
  10. linux端口转发

    2023-12-17 04:50:03       56 阅读
  11. 【pyqt5制作悬浮且透明控件组】

    2023-12-17 04:50:03       56 阅读