浅谈:“阻塞”与“非阻塞”两种赋值语句

FPGA成长的小Tips之赋值语句

深刻理解HDL的阻塞赋值和非阻塞赋值,就一定首先需要理解C语言的阻塞和非阻塞。


文章目录

  • FPGA成长的小Tips之赋值语句
  • 前言背景
  • 一、阻塞赋值(Blocking)与非阻塞赋值(Non_Blocking)是什么?及其赋值过程
  • 二、代码案例
    • 1.阻塞赋值(Blocking)
    • 2.非阻塞赋值(Non_Blocking)
  • 总结


前言背景

在软件层面上,阻塞赋值和非阻塞赋值是一个单纯进程管理的概念。其中阻塞赋值是指当前进程调用函数,函数返回之前,进程被挂起(进程被阻塞);而非阻塞赋值是当前进程调用函数,函数立即返回(返回一个回执),然后进程反复更新所调用函数的返回数据,直到得到有效的返回数据。期间进程不会被挂起(进程非阻塞)。


一、阻塞赋值(Blocking)与非阻塞赋值(Non_Blocking)是什么?及其赋值过程

(1)1.1阻塞赋值使用赋值运算符号为“=”。
阻塞赋值的过程是立刻执行的,即赋值运算符右侧表达式求值完后立刻会更新至运算符左侧,并且这个执行的过程不受其他语句执行的影响,其后的语句只有当前的赋值操作执行完场后才能顺利执行。
1.2所谓阻塞的概念是指在同一个always块中,其后母的赋值语句从概念上是在前一条赋值语句结束后开始赋值的。
(2)2.1非阻塞赋值使用的赋值运算符为“<=”。
2.2非阻塞赋值执行过程:在当前仿真时间槽(time-slot)开始分析计算获得右侧表达式的值,在当前时间槽执行结束时更新左侧表达式的值,在右侧表达式分析计算和左侧表达式被更新之间,任何其他事情都可以执行,同时也可能修改已经计算完成的右侧表达式的值,即非阻塞赋值的过程不影响其他语句的执行。根据非阻塞的特点,其赋值运算符左侧操作数只能为寄存器类型;因此非阻塞赋值只能用于过程性语句中(initial和always),不允许在连续赋值语句中使用非阻塞赋值。

二、代码案例

1.阻塞赋值(Blocking)

代码如下(sysverilog):

module Blocking;

    logic clk;
    logic [3:0] in, q, q_r, q_rr;
    
    initial 
    begin
        clk = 0;
        in = 0;
        q = 1;
        q_r = 2;
        q_rr = 3;
    end 

    always @ (posedge clk)
    begin
        q = in;
        q_r = q;
        q_rr = q_r;
    end 

    always #10 clk = ~clk;

endmodule

通过【VivadoSimulator】仿真观察到,一个时钟周期之后:
下面的语句一直等待上面的语句赋值完成后再执行。
q=0;q_r=0;q_rr=0;
在这里插入图片描述

2.非阻塞赋值(Non_Blocking)

代码如下(Verilog):

module Non_blocking;

    reg clk;
    reg [3:0] in;
    reg [3:0] q, q_r, q_rr;
    
    initial 
    begin
        clk  = 0;
        in   = 0; 
        q    = 1;
        q_r  = 2;
        q_rr = 3;
    end
    
    always @ (posedge clk)
    begin
        q <= in;
        q_r <= q;
        q_rr <= q_r;  
    end

    always #10 clk = ~clk;
    
endmodule

通过观察【ModelSimSimulator】一个时钟周期后:q=0;q_r=1;q_rr=2;
浅谈:“阻塞”与“非阻塞”两种赋值语句_第1张图片


总结

用阻塞赋值感觉就是在一种确定的事情上,如电平敏感的情况下,一旦赋值就“没法回头”。而非阻塞赋值就是为了解决这种“死机”问题,在每次赋值/调用的时候都给一个“反馈”。

你可能感兴趣的:(FPGA,FPGA小Tips,FPGA,面试,fpga开发)