Menu Close

Verilog仿真中fork…join的原理和使用

本文主要给大家介绍如何在仿真中使用fork…join。首先,它的使用格式如下所示:

always 
    fork
    ...
    join

/*或者*/

initial
    fork
    ...
    join

 

可以看到在仿真中fork…join使用方法和begin…end一样。不同的是,begin…end是将语句块中的语句按给定次序顺序执行,而fork…join是将语句块中的语句并行执行。同时要注意,begin…end可以用在综合中,但是fork…join在综合中不支持使用。下面将就fork…join的原理和使用进行介绍。

 

1. 过程语句initial和always

在介绍fork…join语句之前,需要先复习Verilog中的两种结构化过程语句(structed procedure statement):always和initial。这两个语句是行为建模中最基本的两个语句,所有其他的行为语句只能出现在这些结构化的过程语句中。always和initial都是在0时刻执行。always和initial都是独立执行的,并且不可以相互或自身嵌套。

一般在always和initial之后可以接一条行为陈述语句,如果需要接多个行为陈述语句,必须将其分组,通常是通过使用begin…end进行分组。begin…end有些类似于C语言中的 “ { } ”。本文给大家介绍一种另外的分组方法:通过fork…join分组。

 

2.  fork…join原理

由关键字fork…join指定的并行执行的过程语句有以下的特点:

  1. fork…join中所有的并行块语句都是同时执行
  2. 语句执行顺序由分配给每个语句的延迟或事件控制(event control)来控制
  3. 如果指定了延迟或事件控制,则它与进入块的时间有关

注意顺序块(begin…end)和并行块(fork…join)之间的根本区别。 并行块中的所有语句都在进入块时一齐开始执行。 因此,语句在并行块中的写入顺序并不重要

第2点中事件控制举例如下:

@(posedge clock) q = d; //q = d 在信号clock执行时执行

always @( reset, clock, d) q = d; //q= d在reset,clock或是d为高电平时执行

 

3.  fork…join和begin…end相互转换及混合使用

  • begin…end语句

begin…end语句块中的语句按顺序方式执行。每条语句中的延迟值与其前面的语句执行的模拟时间相关。一旦顺序语句执行结束,跟随顺序语句的下一条语句继续执行,如例1所示。

例1:

begin
    #2 pulse = 1;
    #5 pulse = 0;
    #3 pulse = 1;
    #4 pulse = 0;
    #2 pulse = 1;
    #5 pulse = 0;
end

 

如果顺序语句块在时刻0开始执行,那么2个时间单位过去后,pulse = 1,再过5个时间单位,pulse = 0 … 其对应波形如图1所示:

%title插图%num

图1

如果顺序语句块在时刻5开始执行,那么波形会变为如图2所示:

 

%title插图%num

图2

  • fork…join语句

fork…join语句块中的各语句并行执行。fork…join语句块中各条语句指定的延迟值都与fork…join语句块开始执行的时间相关。使用fork…join语句实现例1中同样的波形,如例2所示。

例2:

fork
    #2  pulse = 1;
    #7  pulse = 0;
    #10 pulse = 1;
    #14 pulse = 0;
    #16 pulse = 1;
    #21 pulse = 0;
join

 

如果顺序语句块在时刻0开始执行,那么2个时间单位过去后,pulse = 1,再过5个时间单位,pulse = 0 … 其对应波形如图3所示,与图1一致:

%title插图%num

图3

如果顺序语句块在时刻5开始执行,那么波形会变为如图4所示,与图2一致:

 

%title插图%num

图4

  • 混用begin…end和fork…join语句

注意fork…join和begin…end可以相互或自身嵌套,在fork…join语句块内是并行执行的规则,在begin…end语句块内是顺序执行的规则,如例3所示。

例3:

always
begin:Block_A
    #4 a = 5;           //S1
    
    fork:Blcok_B        //S2
        #6 b = 7;       //P1
        begin:Block_C   //P2
            d = c;      //SS1
            #5 e = d;   //SS2
        end
        #2 f = 3;       //P3
        #4 g = 2;       //P4
        #8 h = 4;       //P5
    join
    
    #8 m = 1;           //S3
    #2 n = 3;           //S4
    #10 $stop;          //S5
end

 

注意例3中每一行语句都被注释了名字,begin…end中的顺序语句被命名为Sequential:S1-S5,SS1-SS2。fork…join中的并行语句被命名为Parallel: P1-P5。

在观察其结果之前,先分析一下这段代码的结构:Block_A是由begin…end引导,所以S1-S5都是顺序执行,即先执行S1,再执行S2…最后执行S5。Block_B是由fork…join引导,所以P1-P5会在进入Block_B后一齐执行。Block_C由begin…end引导,SS1,SS2也是顺序执行的,所以SS1执行完后,才会执行SS2。

例3中语句执行的时间线如图5所示:

%title插图%num

图5

因为例3是在always过程下的语句,所以进入always块后,时刻是0。S1最先执行,所以在第4个时间单位a = 5。顺序执行的S2是fork…join语句,所以之后的P1-P5都是同时执行,按照延时的不同,

  • P1: b = 7在第10(4 + 6)个时间单位执行;
  • P2: SS1和SS2是顺序执行的,所以,SS1先执行:d = c在第4(4 + 0)个时间单位执行,SS2:e = d在第9(4 + 5)个时间单位执行;
  • P3: f = 3 在第6(4 + 2)和时间单位执行;
  • P4: g= 2 在第8(4 + 4)和时间单位执行;
  • P5: h= 4 在第12(4 + 8)和时间单位执行。

在S2执行完后(按最后执行的第12个时间单位开始计算),S3:m = 1在第20(12 + 8)个时间单位执行,S4:n = 3在第22(20 + 2)个时间单位执行,S5:$stop在第32(22 + 10)个时间单位执行。

 

4.  fork…join使用时会产生竞争(race condition)

fork…join语句块提供了并行执行语句的机制。 但是,如果影响同一变量的两个语句并行执行,可能会出现隐式竞争, 如例4所示。

例4:

reg x, y; 
reg x_or_y, x_and_y; 
 
initial 
fork 
    x = 1'b0;       //P1
    y = 1'b1;       //P2
    x_or_y = x | y; //P3
    x_and_y = x & y;//P4
join

 

由于fork…join中的语句在initial过程下,所以进入initial块后,时刻是0。fork…join语句中P1-P4都是并行执行的。在仿真时,fork…join语句块中的所有语句都会立即执行。 然而,实际上,运行模拟的 CPU 一次只能执行一条语句。如果P1和P2先执行,P3和P4后执行,那么x_or_y = 1’b1, x_and_y = 1’b0;如果P3和P4先执行,P1和P2后执行,那么x_or_y 和 x_and_y 的值都是1’bx。因此,x_or_y 和 x_and_y 的结果是不确定的,并且取决于模拟器的实现。不同的模拟器可能以不同的顺序执行并行语句。 因此,竞争是源于现在模拟器的限制,而不是 fork…join 块的限制。

 

5. 总结

借用线程的理念,关键字 fork 可以被视为将单个线程拆分为独立并行的线程。 关键字 join 可以看作是将独立并行的线程连接回单个线程, 在fork…join语句块之间的语句就都是并行执行的。使用fork…join的时候可与begin…end相互对照。在仿真的设计中,可以有多种方法实现激励,描述方式也各不相同,但是最终都可以达到同一个目的。

 

6. 参考文档

  1. Verilog HDL: A Guide to Digital Design and Synthesis
  2. Verilog HDL入门(夏宇闻)
Posted in FPGA, FPGA 教材教案, FPGA开发板, System Verilog, SystemVerilog, Verilog, Verilog, Vivado, Vivado, 开发工具, 开发工具, 开发板, 开发语言, 教材与教案, 文章, 编程语言

发表回复

相关链接