芯路恒电子技术论坛

 找回密码
 立即注册
热搜: 活动
查看: 397|回复: 0

阻塞赋值与非阻塞赋值原理分析

[复制链接]
  • TA的每日心情
    可爱
    2019-5-10 10:58
  • 208

    主题

    371

    帖子

    1万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    10834
    发表于 2019-6-13 17:13:43 | 显示全部楼层 |阅读模式
    1.1 阻塞赋值与非阻塞赋值原理分析
    本节导读
    本章将学习阻塞赋值与非阻塞赋值,并通过四个逻辑实例对其中的区别进行说明。
    阻塞赋值,操作符为“=”,“阻塞”是指在进程语句(initial和always)中,当前的赋值语句会阻断其后语句的正常执行,也就是说后面的语句必须等到当前的赋值语句执行完毕才能执行。而且阻塞赋值可以看成是一步完成的,即:计算等号右边的值并同时赋给左边变量。
    非阻塞赋值,操作符为“<=”,“非阻塞”是指在进程语句(initial和always)中,当前的赋值语句不会阻断其后语句的正常执行。
    1.1.1 不同赋值方式对比与实现
    为了详细说明阻塞赋值与非阻塞赋值对综合之后电路的影响,下面以具体设计进行分析说明。为口列表如下:

      
    module block_nonblock(Clk,Rst_n,a,b,c,out);
      
        input Clk;
      
        input Rst_n;
      
        input a,b,c;
      
    output reg [1:0]out;
      
    //………………………………………//此部分见下
      
    endmodule
      
    首先在时序电路中使用阻塞赋值的方式,描述一个加法器。这种方式实际生成的逻辑电路如图 3.5 1所示。

      
        reg [1:0] d;   
      
        always@(posedge Clk or  negedge Rst_n)
      
        if(!Rst_n)
      
            out  = 2'b0;
      
        else begin
      
             d  =  a + b ;
      
            out  = d +  c;
      
        end   
      
    3.5-1.png
    图 3.5 1 阻塞赋值第一种设计方式
    现在把阻塞赋值的两条语句顺序颠倒一下,再次综合可以得到图 3.5 2所示的逻辑电路。可以看出调整顺序后与不调整时生成的逻辑电路不一致。现结合实验原理给出详细解释,当执行out = d + c时,d的数据此时并不是更新后a+b的数据,而是上一个Clk上升沿到来时d的数据,这也就解释了为何还有一个D触发器的存在。通俗的讲阻塞,out这条语句阻塞了d这条语句执行。对比图11.1的逻辑,由于d这条语句在out的前面,虽然使用了阻塞赋值但是相当于out=a+b+c。

      
        reg  [1:0] d;
      
        always@(posedge Clk or  negedge Rst_n)
      
        if(!Rst_n)
      
            out  = 2'b0;
      
        else begin      
      
            out  = d +  c;
      
             d  =  a + b;
      
        end
      
    3.5-2.png
    图 3.5 2 阻塞赋值第二种设计方式
    现在把赋值方式改为非阻塞赋值,进行综合后可以看到如图 3.5 3所示的逻辑电路。

      
        reg [1:0] d;   
      
        always@(posedge Clk or  negedge Rst_n)
      
        if(!Rst_n)
      
            out  <= 2'b0;
      
        else begin  
      
             d  <=  a + b;   
      
            out  <= d +  c;      
      
        end
      
    3.5-3.png
    图 3.5 3 非阻塞赋值第一种设计方式
    现在使用非阻塞方式,再次交换语句执行顺序,综合后实现的逻辑电路如图 3.5 4所示。这里由于采用的非阻塞赋值,因此交换语句的前后顺序并不会对最终生成的逻辑电路有实际影响。

      
        reg [1:0] d;
      
        always@(posedge Clk or  negedge Rst_n)
      
        if(!Rst_n)
      
            out  <= 2'b0;
      
        else begin      
      
            out  <= d +  c;
      
             d  <=  a + b;
      
        end
      
    3.5-4.png
    图 3.5 4 非阻塞赋值第二种设计方式
    1.1.2 不同赋值方式仿真及测试
    为了在其各自的时序图中更直观的观察效果,新建仿真block_nonblock_tb.v文件保存到testbench文件夹下。本激励文件除产生正常的时钟以及复位信号外,还生成了a、b、c三个信号。这里例化待仿真文件使用的调用方式是显式例化,这种方式要求例化时信号顺序需要与编写的文件顺序一致,且不能在一个激励文件中例化两次。可以看出这种方式容易出错,且具有局限性,因此不推荐使用,本书之后的例程不再采用,此处只做介绍。
      
    `timescale 1ns/1ns
      
    `define clock_period 20
      
      
    module block_nonblock_tb;
      
      
        reg Clock;
      
        reg Rst_n;
      
        reg a,b,c;
      
       
      
        wire [1:0out;
      
       
      
        block_nonblock block_nonblock0(Clock,Rst_n,a,b,c,out);
      
       
      
        initial  Clock = 1;
      
        always#(`clock_period/2) Clock = ~Clock;
      
       
      
        initial begin
      
            Rst_n = 1'b0;
      
            a = 0;
      
            b = 0;
      
            c = 0;
      
            #(`clock_period*200 + 1);
      
            Rst_n = 1'b1;
      
            #(`clock_period*200);
      
            a = 0  ; b = 0 ; c = 0;
      
            #(`clock_period*200);
      
            a = 0  ; b = 0 ; c = 1;
      
            #(`clock_period*200);
      
            a = 0  ; b = 1 ; c = 0;
      
            #(`clock_period*200);
      
            a = 0  ; b = 1 ; c = 1;
      
            #(`clock_period*200);   
      
            a = 1  ; b = 0 ; c = 0;
      
            #(`clock_period*200);
      
            a = 1  ; b = 0 ; c = 1;
      
            #(`clock_period*200);
      
            a = 1  ; b = 1 ; c = 0;
      
            #(`clock_period*200);
      
            a = 1  ; b = 1 ; c = 1;
      
            #(`clock_period*200);
      
            #(`clock_period*200);
      
            $stop;  
      
        end
      
      
    endmodule
      

    设置好仿真脚本后,进行非阻塞赋值方式的功能仿真,可以看到如图 3.5 5所示的波形文件,可以看出在复位信号置高之前输出为0。直观看上去没有问题,现在放大细节可以看出如图 3.5 6。
    3.5-5.png
    图 3.5 5 非阻塞赋值整体功能仿真图
    变化在第一个时钟上升沿之后,因此第一个时钟沿检测不到,下一个时钟检测到011 直接赋值计算。
    3.5-6.png
    图 3.5 6 非阻塞赋值部分功能仿真图
    继续放大细节可得图 3.5 7,在第一个上升沿out的值依旧为0,设计虽然采用非阻塞赋值方式,且此刻d值已经更新为1,但是实际电路中总会存在延迟,这个时钟沿时刻out已经采样不到当前d的值,继续保持数值0。为了更好的解释这种现象,现进行时序仿真。
    3.5-7.png
    图 3.5 7 非阻塞赋值部分功能仿真图
            全编译后进行时序仿真,可以在图 3.5 8清晰的看出这种现象。
    3.5-8.png
    图 3.5 8 非阻塞赋值时序仿真图
    再次改为另一种非阻塞赋值方式,如下所示综合出来如图 3.5 9所示。可以与图3.51比较分析。

      
        always@(posedge Clk or negedge Rst_n)
      
        if(!Rst_n)
      
            out <=  2'b0;
      
        else begin  
      
            out <=  a + b + c;      
      
        end
      
    3.5-9.png
    图 3.5 9 非阻塞赋值第三种设计方式
    本章对比了 Verilog 语法中阻塞赋值和非阻塞赋值的区别。通过证明非阻塞赋值多种赋值顺序生成电路的唯一性,与阻塞赋值多种赋值顺序生成电路的不确定性,来展示使用非阻塞赋值对设计可预测性的重要意义。在今后的设计中会经常用到两种赋值方式,请多加思考其中区别及意义。
    在今后的设计中,掌握以下六个原则,可解决在综合后仿真中出现绝大多数的冒险竞争问题。
    1) 时序电路建模时,用非阻塞赋值;
    2) 锁存器电路建模时,用非阻塞赋值;
    3) 用always块建立组合逻辑模型时,用阻塞赋值;
    4) 在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值;
    5) 在同一个always块中不要既用非阻塞赋值又用阻塞赋值;
    6) 不要在一个以上的always块中为同一个变量赋值。


    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|小黑屋|手机版|Archiver|芯路恒电子技术论坛  

    GMT+8, 2019-10-19 13:55 , Processed in 0.334660 second(s), 14 queries , File On.

    Powered by Discuz! X3.3

    © 2001-2017 Comsenz Inc. Template By 【未来科技】【 www.wekei.cn 】

    快速回复 返回顶部 返回列表