• Verilog 过程赋值(阻塞赋值,非阻塞赋值,并行)


            过程性赋值是在 initial 或 always 语句块里的赋值,赋值对象是寄存器、整数、实数等类型。这些变量在被赋值后,其值将保持不变,直到重新被赋予新值。连续性赋值总是处于激活状态,任何操作数的改变都会影响表达式的结果;过程赋值只有在语句执行的时候,才会起作用。这是连续性赋值与过程性赋值的区别。

    Verilog 过程赋值包括 2 种语句:阻塞赋值与非阻塞赋值。

    阻塞赋值

            阻塞赋值属于顺序执行,即下一条语句执行前,当前语句一定会执行完毕。阻塞赋值语句使用等号 = 作为赋值符。前面的仿真中,initial 里面的赋值语句都是用的阻塞赋值。

    非阻塞赋值        

            非阻塞赋值属于并行执行语句,即下一条语句的执行和当前语句的执行是同时进行的,它不会阻塞位于同一个语句块中后面语句的执行。非阻塞赋值语句使用小于等于号 <= 作为赋值符。

    利用下面代码,对阻塞、非阻塞赋值进行仿真,来说明 2 种过程赋值的区别。

    1. Example1:
    2. `timescale 1ns/1ns
    3. module test ;
    4. reg [3:0] ai, bi ;
    5. reg [3:0] ai2, bi2 ;
    6. reg [3:0] value_blk ;
    7. reg [3:0] value_non ;
    8. reg [3:0] value_non2 ;
    9. initial begin
    10. ai = 4'd1 ; //(1)
    11. bi = 4'd2 ; //(2)
    12. ai2 = 4'd7 ; //(3)
    13. bi2 = 4'd8 ; //(4)
    14. #20 ; //(5)
    15. //non-block-assigment with block-assignment
    16. ai = 4'd3 ; //(6)
    17. bi = 4'd4 ; //(7)
    18. value_blk = ai + bi ; //(8)
    19. value_non <= ai + bi ; //(9)
    20. //non-block-assigment itself
    21. ai2 <= 4'd5 ; //(10)
    22. bi2 <= 4'd6 ; //(11)
    23. value_non2 <= ai2 + bi2 ; //(12)
    24. end
    25. //stop the simulation
    26. always begin
    27. #10 ;
    28. if ($time >= 1000) $finish ;
    29. end
    30. endmodule

    使用非阻塞赋值避免竞争冒险

            上述仿真代码只是为了让读者更好的理解阻塞赋值与非阻塞赋值的区别。实际 Verilog 代码设计时,切记不要在一个过程结构中混合使用阻塞赋值与非阻塞赋值。两种赋值方式混用时,时序不容易控制,很容易得到意外的结果。更多时候,在设计电路时,always 时序逻辑块中多用非阻塞赋值,always 组合逻辑块中多用阻塞赋值;在仿真电路时,initial 块中一般多用阻塞赋值。

            如下所示,为实现在时钟上升沿交换 2 个寄存器值的功能,在 2 个 always 块中使用阻塞赋值。因为 2 个 always 块中的语句是同时进行的,但是 a=b 与 b=a 是无法判定执行顺序的,这就造成了竞争的局面。但不管哪个先执行(和编译器等有关系),不考虑 timing 问题时,他们执行顺序总有先后,最后 a 与 b 的值总是相等的。没有达到交换 2 个寄存器值的效果。

    1. Example2:
    2. always @(posedge clk) begin
    3. a = b ;
    4. end
    5. always @(posedge clk) begin
    6. b = a;
    7. end

    但是,如果在 always 块中使用非阻塞赋值,则可以避免上述竞争冒险的情况。
            如下所示,2 个 always 块中语句并行执行,赋值操作右端操作数使用的是上一个时钟周期的旧值,此时 a<=b 与 b<=a 就可以相互不干扰的执行,达到交换寄存器值的目的。

    1. Example3:
    2. always @(posedge clk) begin
    3. a <= b ;
    4. end
    5. always @(posedge clk) begin
    6. b <= a;
    7. end

    当然,利用下面代码也可以实现交换寄存器值的功能,但是显然不如在 always 块中直接用非阻塞赋值简单直观。

    1. Example4:
    2. always @(posedge clk) begin
    3.     temp    = a ;
    4.     a       = b ;
    5.     b       = temp ;
    6. end

  • 相关阅读:
    应用在汽车发动机温度检测中的高精度温度传感芯片
    linux特殊权限
    php 进程池设计与实现,phper必学!
    CountDownLatch
    天府杯E题
    C++STL【string】下模拟实现string
    对家自动驾驶汽车出 Bug?马斯克幸灾乐祸:“哈哈!”
    【Shell】算术运算符、流程控制、函数使用、数组以及加载其它文件的变量
    深度学习标注工具(包括自动标注)总结——持续更新
    ubuntu 多版本cmake共存的终极方法
  • 原文地址:https://blog.csdn.net/qq_33300585/article/details/127863860