精华内容
下载资源
问答
  • 阻塞赋值与非阻塞赋值

    千次阅读 2016-07-19 20:57:32
    阻塞赋值与非阻塞赋值的区别———摘自《数字系统设计教程》 1.非阻塞(Non_Blocking)赋值(如b) (1)在语句块中,上面语句所赋的变量值不能立即就为下面的语句所用; (2)块结束后才能完成这次赋值操作,而...

    阻塞赋值与非阻塞赋值的区别———摘自《数字系统设计教程》
    1.非阻塞(Non_Blocking)赋值(如b<=a)
    (1)在语句块中,上面语句所赋的变量值不能立即就为下面的语句所用;
    (2)块结束后才能完成这次赋值操作,而所赋的变量值是上一次赋值得到的;
    (3)在编写可综合的时序逻辑模块时,这是最常用 的赋值方法。
    2.阻塞(blocking)赋值方式(如b=a;)
    (1)赋值语句执行完后,块才结束;
    (2)b的值在赋值语句执行完后立刻就改变的;
    (3)在时序逻辑中使用时,可能会产生意向不到的结果。

    举例:1
    always @(posedge clk)
    begin
    b <= a;
    c <= b;
    end
    上述实例中用了非阻塞赋值方式,定义了两个reg型信号b和c。clk信号的上升沿到来时,b就等于a,c就等于b(原始值),这里用到了两个触发器。
    注意:赋值在“always”块结束后执行的,c应为原来b的值。这个always块实际描述的电路功能如图1所示。
    图1
    例2:
    always @(posedge clk)
    begin
    b = a;
    c = b;
    end
    例2采用了阻塞赋值方式。clk信号的上升沿到来时,将发生如下变化:b马上去a的值,c马上取b的值(即等于a),生成如图2所示的电路。图中只用了一个触发器来寄存a的值,又输出给b和c。
    图2

    展开全文
  • Verilog十大基本功0(阻塞赋值与非阻塞赋值阻塞赋值与非阻塞赋值超级详细讲解 本文共分为三部分: 第一部分是正确使用阻塞与非阻塞赋值的基本原则。 第二部分是阻塞与非阻塞赋值对应的电路行为逻辑。 第三部分是...

    Verilog十大基本功0(阻塞赋值与非阻塞赋值)阻塞赋值与非阻塞赋值超级详细讲解

    本文共分为三部分:
    第一部分是正确使用阻塞与非阻塞赋值的基本原则。
    第二部分是阻塞与非阻塞赋值对应的电路行为逻辑。
    第三部分是阻塞与非阻塞赋值的原理简介。

    第一部分 正确使用阻塞与非阻塞赋值的基本原则(Golden Rule)
    编码原则很多,就阻塞非阻塞赋值而言,新手最需要牢记的是其中三条:
    1、时序逻辑一定用非阻塞赋值”<=”,一旦看到敏感列表有 posedge 就用”<=”。
    2、组合逻辑一定用”=” ,一旦敏感列表没有 posedge 就用”=”,一旦看到 assign 就用”=”。
    3、时序逻辑和组合逻辑分成不同的模块,即一个 always 模块里面只能出现非阻塞赋值”<=”或者”=”。如
    果发现两种赋值并存,一个字”改”,心存侥幸可能会给后续工作带来更多麻烦。

    以上三条,对新手而言不必追求为什么,需要的就是条件反射的照章办事。最后说一句,新手可能记不
    住哪个符号是阻塞赋值,哪个是非阻塞赋值,大家可以数数, ”非阻塞赋值”一共 5 个字,“阻塞赋值“ 4
    个字,所以非阻塞用的符号”<=”比阻塞赋值用的符号”=”长。


    第二部分 阻塞与非阻塞赋值对应的电路行为逻辑
    第一节给出了三条最基本的编码原则,有个朋友可能会想,按照这三条编码原则写出来的代码会按怎样
    的逻辑工作呢?这一节就是回答这个问题。

    首先解释一下阻塞赋值与非阻塞赋值的含义。
    所谓的阻塞赋值”=”就是说, 在这个语句没有执行完之前,后面的语句是不执行的。 
    这里执行的含义是指完成变量值的更新。
    非阻塞赋值”<=”是指, 所有的语句可以并发执行,而前面的值是否执行完毕不会影响后面的语句,
    换句话说,语句的顺序是无关紧要的。

    举个例子,假设一个模块,有 2 个寄存器, b 和 c,初值都是 1。 a 为输入信号线。在某个时刻,因为某
    种原因,模块被触发执行。对于组合逻辑而言,一般是输入信号值变了,对于时序逻辑而言,一般是时
    钟沿到了。

    首先看组合逻辑:假设输入 a = 2;
    always@(a ,b)
    begin
      b = a;
      c = b;
    end

    由于是阻塞赋值,所以首先执行完第一句 b=a,执行完成之后 b=2。接着执行 c=b,执行完成后 c=2,一
    次仿真结束后 b=c=2;

    对于时序逻辑而言,依然假设 a =2;
    always@(posedge clk)
    begin
      b <= a;
      c <= b;
    end

    由于是非阻塞赋值,首先执行第一句 b<=a,这时候 a = 2,但是还没有执行完第一句的时候,第二句 c<=b
    也执行了,由于第一句没有执行完, b 的值还是 1,这时候赋值给 c 的值也是 1。执行完毕的结果就是
    c=1,b=2.等到模块再次被触发的时候 c 的值更新为 2。

    第三部分 阻塞与非阻塞赋值的原理简介
    有个朋友可能就会问了,凭啥第一句执行到一半就该第二句执行呢?到底是第一句先完成赋值呢还是第二句
    先完成赋值?答案是,谁先完成赋值都没关系,结果是一样的。

    为什么说结果一样呢? 因为两种赋值方式分别是按照下面的顺序执行的。

    阻塞赋值,就跟 C 语言一样,严格按照代码书写的先后顺序执行,所有值都是立即更新,并且在下面的
    语句中按照新值执行。

    而时序电路就不一样了,大家可以这么理解时序逻辑的代码行为,一次执行分为两轮:
    第一轮是所有的左值都先赋给临时变量,
    第二轮用输入值以及和右值同名的临时变量值去更新左值。

    比如上面的例子,第一轮,赋给临时变量: tempc=c;tempb=b。
    第二轮,临时变量更新左值, b = a;c = tempb;output = tempc。
    从上面的分析也可以看出,组合逻辑的结果与代码顺序直接相关,而时序逻辑与代码顺序没有关系。这就是所
    谓的顺序执行(组合逻辑)与并发执行(时序逻辑)。

    为了进一步理解这两种赋值方式的行为,下面用对应的电路进行说明,以前面的代码为例。大家首先闭
    上眼睛想想,对应的电路是什么样子的呢?

    其实答案很简单,对于阻塞赋值来说,如图一所示,综合的结果就是一根导线,当然,可能有反相器,
    buf 什么的,反正还是可以看作一根线。

    到这里,应该就很容易理解顺序执行的行为方式了。
    有细心的朋友可能会问,如果换种写法呢?

    always@(a,b)
    begin
      c = b;
      b = a;
    end

    很显然,这种电路的行为跟之前是不一样的,从逻辑来看会产生类似于非阻塞赋值的结果,但很显然不
    满足非阻塞赋值并发执行的特点。如果把输入电平 a 触发改成时钟边沿触发 posedge clk,出来的就是寄
    存器,但这违反了时序逻辑不用阻塞赋值的原则,所以严重不推荐。至于这种组合逻辑描述方式出来的
    电路是啥我也不知道,大家可以自己综合看看,或者哪位高人补上~~应该注意的是,如果想象不出这种
    怪异的 coding 方式会产生何种电路,就不要这么写,因为实现这种逻辑最好的办法是采用非阻塞方式描
    述。

    而对于非阻塞赋值而言,综合出来的结果就是 2 个寄存器。对 b,c 赋值的过程就是寄存器
    输入采样的过程,很显然两个采样是同时进行的,而且一次时钟沿只会采样一次,所以输入值 a 会首先
    被采样到 b,再在下一个时钟被采样到 c.

    总结一下:
    关于两种赋值方式,首先讲述了代码执行的过程,然后用直连线和寄存器分别对应了两种描
    述方式。应该指出的是,非阻塞赋值用寄存器的类比是完全准确的,而阻塞赋值用直连线的类比却未必
    准确,只不过因为一般认为直连线是从输入到输出依次更新的,而且没有传输以外的延迟,所以这种类
    比有助于新人理解,虽然不够严密。大家熟悉了之后就应该按照更严谨的方式去理解。

    补充一下,如果写出下面这样的代码,在时序电路中使用阻塞赋值的话,综合出来就只有一个寄存器,不是两个,寄
    存器的输入 D 端是 a,输出 Q 端是 b 和 c,两个信号在同一根线上

    always@(posedge clk)
    begin
      b = a;
      c = b;
    end

    所以这样的写法很容易造成设计和综合结果不匹配的情况,即使不是要设计两级寄存器,也最好不要用阻塞赋值。

    另外一个就是,脑袋里面需要有时序逻辑和组合逻辑的框图。
    将组合逻辑和时序逻辑分开写,组合逻辑用=,时序逻辑用<=,
    时序逻辑内的判断越简单越好,尽量都放在组合逻辑里面做,时序逻辑只负责 flop 一下。
    所以,最重要的是, 新手应该严格按照规则来,见到 posedge 就写 <= ,而根本不考虑 = ,免得综合出怪东西来。
    这种代码应该严格杜绝,呵呵~~
    ————————————————
    版权声明:本文为CSDN博主「Times_poem」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/Times_poem/article/details/52032890

    展开全文
  • FPGA中阻塞赋值与非阻塞赋值原理实验
  • 最近学到了关于verilog的阻塞赋值与非阻塞赋值的一些区别,经过网上查阅与仿真实验,有了一些理解。希望能够记下来。
  • Verilgo 阻塞赋值与非阻塞赋值 时间:2018.8.21 地点:信电院办 内容:verilgo 中阻塞赋值和非阻塞赋值的区别以及应用 阻塞赋值与非阻塞赋值: 1.阻塞赋值“=”(组合逻辑电路),非阻塞赋值“&lt;=”...
             Verilgo 阻塞赋值与非阻塞赋值
    

    时间:2018.8.21
    地点:信电院办
    内容:verilgo 中阻塞赋值和非阻塞赋值的区别以及应用

    阻塞赋值与非阻塞赋值:

    1.阻塞赋值“=”(组合逻辑电路),非阻塞赋值“<=”(时序逻辑电路);

    2.Verilog模块编程的8个原则:

    (1) 时序电路建模时,用非阻塞赋值。

    (2) 锁存器电路建模时,用非阻塞赋值。

    (3) 用always块建立组合逻辑模型时,用阻塞赋值。

    (4) 在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值。

    (5) 在同一个always块中不要既用非阻塞赋值又用阻塞赋值。

    (6) 不要在一个以上的always块中为同一个变量赋值。

    (7) 用$strobe系统任务来显示用非阻塞赋值的变量值。

    (8) 在赋值时不要使用#0延时。

    在编写时牢记这八个要点可以为绝大多数的Verilog用户解决在综合后仿真中出现的90-100% 的冒险竞争问题。

    3.所谓阻塞的概念是指在同一个always块中,其后面的赋值语句从概念上是在前一条赋值语句结束后开始赋值的。
    4.非阻塞语句的执行过程是:首先计算语句块内部所有右边表达式(RHS)的值,然后完成对左边寄存器变量的赋值操作。

    5.阻塞赋值与非阻塞赋值的本质区别:
      非阻塞赋值语句右端表达式计算完后并不立即赋值给左端,而是同时启动下一条语句继续执行,可以将其理解为所有的右端表达式RHS1、RHS2等在进程开始时同时计算,计算完后 ,等进程结束时同时分别赋给左端变量LHS1、LHS2等;
    而阻塞赋值语句在每个右端表达式计算完后立即赋给左端变量,即赋值语句LHS1=RHS1执行完后LHS1是立即更新的,同时只有LHS1=RHS1执行完后才可执行语句LHS1=RHS2,依次类推。前一条语句的执行结果直接影响到后面语句的执行结果。
    简单地说,阻塞赋值是并行执行的:
    例如:

    qout[0] =qout[0];
    qout[1] =qout[1];
    qout[2] =qout[2];
    这组阻塞赋值语句执行过程是并行执行的,三条语句是同时执行的
    

    qout[0] <=qout[0];
    qout[1] <=qout[1];
    qout[2] <=qout[2];

    “`
    这组非阻塞赋值语句是顺序执行的      

                                                                                                                                              未完待续

    展开全文
  • 以下从两个典型的例子以及多个角度去分析得到与验证阻塞赋值与非阻塞赋值的区别,以及各自的特点。 非阻塞赋值与阻塞赋值特性 1、非阻塞赋值的特性: 赋值语句的流程: a)计算右边的表达式得到结果 b)将结果...

    博主福利:100G+电子设计学习资源包!

    http://mp.weixin.qq.com/mp/homepage?__biz=MzU3OTczMzk5Mg==&hid=7&sn=ad5d5d0f15df84f4a92ebf72f88d4ee8&scene=18#wechat_redirect
    --------------------------------------------------------------------------------------------------------------------------

     

    据说阻塞赋值和非阻塞赋值是Verilog 语言中最难理解的知识点之一,我也觉得,从网上翻阅了资料,也看过一些视频。

    以下从两个典型的例子以及多个角度去分析得到与验证阻塞赋值与非阻塞赋值的区别,以及各自的特点。
      

    非阻塞赋值与阻塞赋值特性

    1、非阻塞赋值的特性:

    赋值语句的流程:

    a)计算右边的表达式得到结果

    b)将结果赋值到左边的变量

    这个过程中允许来自任何其他Verilog语句的干扰,也就是说其他Verilog语句都可以在这个时候执行。

    2、阻塞赋值特性:

    赋值语句的流程:

    c)计算右边的表达式得到结果

    d)将结果赋值到左边的变量

    这个过程中不允许有来自任何其他Verilog语句的干扰,这就导致其他的Verilog语句会等待(阻塞)该赋值语句执行完毕后才能被执行,这就是阻塞的含义。

     

    一、非阻塞赋值分析

    1、非阻塞赋值源程序

    /* 实验名称:非阻塞赋值 */

    module mytest(clk, rst_n, a, b, c, out);

     

        input clk, rst_n, a, b, c;

        output reg [1:0]    out;   

        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

     

    endmodule

     

    从源码中分析,根据非阻塞语句的特性, 假设 a = 0,b = 1, c = 0;

    当rst_n为高时,由于d<=a+b、out<=d+c; 是同时执行,所以:

    1、先右边表达式的结果:a + b = 0 + 1 = 1、d + c = 0 + 0 = 0

    2、再将结果赋值给左边: d = a + 1就等于 1,out = d + c 就等于 0

     

    2、RTL视图

     

        其实RTL视图中也能看出来,假设a = 0,b = 1, c = 0; d寄存器为0,out寄存器为0 ;

    那么当一个时钟周期到来:(以下两步会同时执行,即d与out寄存器会同时从加法器中取值)

    1、Add0寄存器会将a(0) + b(1) = 1的值给d寄存器,d寄存器由0变为1

    2、Add1寄存器会将d(0) + c(0) = 0的值给out寄存器,out寄存器仍是0

     

    3、仿真测试源程序

    `timescale 1ns/1ns

    `define clock_period 20

     

    module mytest_tb;

     

        reg clk, rst_n, a, b, c;

        wire [1:0] out;

       

        mytest u1(clk, rst_n, a, b, c, out);

       

        initial clk = 1;

        always#(`clock_period / 2) clk = ~clk;

       

        initial begin

            rst_n = 1'b0;

            a = 0;

            b = 0;

            c = 0;

            #(`clock_period * 200 + 1);

            rst_n = 1'b1;

            #(`clock_period * 20);

           

            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

     

    4、波形图

     

    5、波形分析
     

    这是 out 从 0 变成 1 前一个时钟周期的情况,由上图可以看到,当时钟上升沿,采样得到的 a、b、d、c都是等于0,而c是在时钟上升沿之后才被拉高,所以要在下一个时钟周期的上升沿才能采样到c的状态,

    如下图:

     

    然后我们再往后看看。

     

    首先我们看到 01 与 01 直接夹着 0,那么01对应的应该是如下几行的测试代码,从代码可以看到不应该有00的存在。

    a = 0; b = 0; c = 1;

    #(`clock_period * 200);

    a = 0; b = 1; c = 0;

    #(`clock_period * 200);

    因为c变为0,b变为1是在时钟周期的上升沿之后才变化,这里暂时不考虑是在上升沿或下降沿时变化。

    而out和d的状态因为过程中需要采样和赋值操作,会有一个逻辑延迟的现象,也就是说也是在时钟上升沿之后才会变化。以下为后仿真的波形图,根据接近实际状况。

     

    即图中A上升沿时:(以下两步的采样是在同一个时钟上升沿同时进行)

    1、d的状态:旧状态是0,经过以下操作新的状态是0

    同时采样a的状态得到是0,b的状态得到的是0。所以d的状态变为0

    2、out的状态:旧状态是1,经过以下操作新的状态变为1

    同时到d是0,c的状态得到的是1,所以导致out变为1。

        3、在时钟为稳定电平期间c变为0,b变为1,即在上升沿之后。

     

    那么到了B上升沿时:(以下两步的采样是在同一个时钟上升沿同时进行)

    1、d的状态:旧状态是0,经过以下操作新的状态是1

    同时采样a的状态得到是0, b的状态得到的是1。所以d的状态变为1

    2、out的状态:旧状态是1,经过以下操作新的状态变为0

    同时采样到d是0,c的状态得到的是0,所以导致out变为0。

     

    当到C上升沿的时:(以下两步的采样是在同一个时钟上升沿同时进行)

    1、d的状态:旧状态是1,经过以下操作新的状态是1

    同时采样a的状态得到是0,b的状态得到的是1。所以d的状态变为1

    2、out的状态:旧状态是0,经过以下操作新的状态变为1

    同时采样到d是1,c的状态得到的是0,所以导致out变为0。

     

    6、解决出现0的情况。

        分析原因:

    从RTL视图中可以看到是因为多了几个d寄存器导致out寄存器慢了一个时钟。

        从波形视图中可以看到也是因为多了d,导致out寄存器出现了0状态。

        结论:

    将d去掉即可,以后写程序过程中尽量不要采用中间变量,避免出现多余的寄存器出现,导致不同步。

     

        源程序如下:

        `timescale 1ns/1ns

    /* 实验名称:非阻塞赋值 */

    module mytest(clk, rst_n, a, b, c, out);

     

        input clk, rst_n, a, b, c;

        output reg [1:0]    out;

       

        //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;

                out <= a + b + c;

            end

     

    endmodule

     

    RTL视图:(从下图可以看到,来一个时钟周期,那么out直接就取Add0和Add1的值)

     

        波形图:(下图比较小,可以对比上面的波形图)

     

    二、阻塞赋值分析

    1、源程序(为了更加清晰的理解,我修改了视频作者的源码)

    `timescale 1ns/1ns

    /* 实验名称:非阻塞赋值 */

    module mytest(clk, rst_n, a, b, c, out);

     

        input clk, rst_n, a, b, c;

        output reg [1:0]    out;

     

        reg[1:0] d;

        reg run;        // 这个是用来指示当前执行的位置

       

        always@(posedge clk or negedge rst_n)

            if(!rst_n)

                out = 2'b0;

            else begin

                d = a + b;

                run =#1 1;    // 准备执行out赋值时

                out = d + c;

                run =#1 0;    // 执行out赋值后

            end

     

    endmodule

     

    从源码中分析,根据阻塞语句的特性, 假设 a = 0,b = 1, c = 0;

    当rst_n为高时,由于d=a+b、out=d+c; 是顺序执行,所以:

    1、先执行:d = a + b = 0 + 1 = 1

    2、在执行:out = d + c = 1 + 0 = 1;

     

    2、RTL视图(没看错,就和去掉了d寄存器的非阻塞赋值代码生成的电路一样)

        从这里就能看出与非阻塞赋值的不同之处,此处不再解释。

     

    3、仿真测试程序   

    与非阻塞仿真测试程序一样,略。

     

    4、波形图

     

    5、波形图分析

     

    根据代码我们知道run信号是执行完d = a + b 之后为高电平,执行完 out = d + c 为低电平。

    通过run信号知道,每次都是在out变化之后才出现低电平。因为如果是同时执行的话,速度非常快,由于run原先就是低电平,变为高电平和变为低电平都是延时1ns,也就是说同时执行1ns之后run依然会是低电平,如下图,同样的延时,改为非阻塞的方式,out一直为低。

     

    A时钟上升沿到来:(以下三个步骤为顺序执行)

        1、d的状态:当前状态0,经过采样,新的状态更新为0

            同时采样a的状态为0、 b的状态为0,d = a + b = 0 + 0 = 0;

        2、run信号:

            被拉高

        3、out的状态:当前状态0,经过采样,新的状态更新为0

            同时采样d的状态0、c的状态为0,out = d + c = 0 + 0 = 0;

    4、run信号:

    被拉低

     

    B时钟上升沿到来:(以下三个步骤为顺序执行)

        1、d的状态:当前状态0,经过采样,新的状态更新为0

            同时采样a的状态为0、 b的状态为0,d = a + b = 0 + 0 = 0;

        2、run信号:

            被拉高

        3、out的状态:当前状态0,经过采样,新的状态更新为1

            同时采样d的状态0、c的状态为1,out = d + c = 0 + 1 = 1;

    4、run信号:

    被拉低

     

    C时钟上升沿到来:(以下三个步骤为顺序执行)

        1、d的状态:当前状态0,经过采样,新的状态更新为0

            同时采样a的状态为0、 b的状态为0,d = a + b = 0 + 0 = 0;

        2、run信号:

            被拉高

        3、out的状态:当前状态1,经过采样,新的状态更新为1

            同时采样d的状态0、c的状态为1,out = d + c = 0 + 1 = 1;

    4、run信号:

    被拉低

     

    通过以上步骤可以发现,执行的时间、采样的时间不一样,会导致不一样的结果。

     

    一、非阻塞赋值分析

    1、非阻塞赋值例程

    /* 实验名称:阻塞与非阻塞赋值差异实验

     * 程序功能:非阻塞赋值 - 观看 RTL-View 以及波形 */

    module mytest(o_y1, o_y2, i_clk, i_rst);

     

        output reg o_y1, o_y2;

        input wire i_clk, i_rst;

       

        //异步复位 alwaysA

        always@(posedge i_clk or negedge i_rst)

            if(!i_rst)    

    o_y1 <= 0;        // 低电平复位

            else        

    o_y1 <= o_y2;

       

        //异步复位 alwaysB

        always@(posedge i_clk or negedge i_rst)

            if(!i_rst)   

    o_y2 <= 1;        // 低电平复位

            else       

    o_y2 <= o_y1;

           

    endmodule

     

    2、RTL 视图

     

    3、仿真源程序

    `timescale 1ns/1ns

    `define clock_period 20

     

    module mytest_tb;

     

        reg clk, rst;

        wire y1, y2;

     

        mytest u1(y1, y2, clk, rst);

       

        initial clk = 1'b1;

        always #(`clock_period / 2) clk = ~clk;

       

        initial begin

            rst = 1'b0;                    // 复位

            #(`clock_period * 5);

            rst = 1'b1;                    // 开始执行

            #(`clock_period * 20);

           

            rst = 1'b0;

            #(`clock_period * 5);

            rst = 1'b1;

            #(`clock_period * 20);

           

            rst = 1'b0;

            #(`clock_period * 5);

            rst = 1'b1;

            #(`clock_period * 20);

           

            $stop;

        end

     

    endmodule

     

    4、波形图

     

    5、波形分析

    //异步复位 alwaysA

        always@(posedge i_clk or negedge i_rst)

            if(!i_rst)    

    o_y1 <= 0;        // 低电平复位

            else        

    o_y1 <= o_y2;

       

    //异步复位 alwaysB

        always@(posedge i_clk or negedge i_rst)

            if(!i_rst)   

    o_y2 <= 1;        // 低电平复位

            else       

    o_y2 <= o_y1;

     

    当 i_rst == 0 :o_y1 被赋值为 0, o_y2 被赋值为 1,由于非阻塞赋值特性,所以无先后顺序

    当 i_rst == 1 :由于两个 always 块会被同时执行。即 fpga 会在同一个时钟上升沿进行采样,

    第一个时钟周期:

    alwaysA 会对 o_y2 采样得到为高电平,所以给 o_y1 赋值为高电平。

    alwaysB 会对 o_y1 采样得到为低电平,所以给 o_y2 赋值为低电平。

    第二个时钟周期:

    alwaysA 会对 o_y2 采样,因为在第一个周期中 o_y2 因 o_y1 而赋值为低电平,所以采样得到为低电平,所以给 o_y1 赋值为低电平。

    alwaysB 会对 o_y1 采样,因为在第一个周期中 o_y1 因 o_y2 而赋值为高电平,所以采样得到为高电平,所以给 o_y2 赋值为高电平。

    之后的时钟周期都是根据这样的规律进行变化,所以我们看到的波形 o_y1、o_y2 是相反状态。

     

    二、阻塞赋值分析

    1、阻塞赋值源程序

    /* 实验名称:阻塞与非阻塞赋值差异实验

     * 程序功能:阻塞赋值 - 观看 RTL-View 以及波形

     */

    module mytest(o_y1, o_y2, i_clk, i_rst);

     

        output reg o_y1, o_y2;

        input wire i_clk, i_rst;

       

        //异步复位

        always@(posedge i_clk or negedge i_rst)

            if(!i_rst)    

                o_y1 = 0;        // 低电平复位

            else        

                o_y1 = o_y2;

     

        //异步复位

        always@(posedge i_clk or negedge i_rst)

            if(!i_rst)   

                o_y2 = 1;        // 低电平复位

            else       

                o_y2 = o_y1;

           

    endmodule

     

    2、RTL 视图(居然和阻塞一样的 RTL 视图)

    3、仿真源程序

    和非阻塞仿真源程序一样。略

    3、波形图

     

    4、波形分析

    //异步复位alwaysA

        always@(posedge i_clk or negedge i_rst)

            if(!i_rst)    

                o_y1 = 0;        // 低电平复位

            else        

                o_y1 = o_y2;

       

        //异步复位 alwaysB

        always@(posedge i_clk or negedge i_rst)

            if(!i_rst)   

                o_y2 = 1;        // 低电平复位

            else       

                o_y2 = o_y1;

     

    当 i_rst == 0 :o_y1 被赋值为 0, o_y2 被赋值为 1, 由于阻塞赋值特性,所以有先后顺序,但无法确定谁先谁后。

    当 i_rst == 1 :由于阻塞赋值的特性,在执行阻塞赋值语句时其他语句均不能得到执行。由于两个 always 块会被同时执行,而且 o_y1 和 o_y2 的取值是互相影响,所以 o_y1、o_y2 值取决于那个 always 块的赋值语句先执行。从波形来看,明显是 alwaysA 最新得到执行。

    第一个时钟周期:

    alwaysA 会对 o_y2 采样得到为高电平,所以给 o_y1 赋值为高电平。

    alwaysB 会对 o_y1 采样,因在 alwaysA 程序块 o_y1 因 o_y2 而赋值为高电平,所以给 o_y2 赋值为高电平。

     

    第二个时钟周期:

    alwaysA 会对 o_y2 采样,因为在第一个周期中 o_y2 因 o_y1 而赋值为高电平,所以采样得到为高电平,所以给 o_y1 赋值为高电平。

    alwaysB 会对 o_y1 采样,因在 alwaysA 程序块 o_y1 因 o_y2 而赋值为高电平,所以给 o_y2 赋值为高电平。

     

    也就是说 o_y1 = o_y2; o_y2 = o_y1; 是顺序执行的,所以我们看到的波形 o_y1、o_y2 都是高电平状态.


    最后附上非阻塞赋值的一个很有意思的例子。

    展开全文
  • 阻塞赋值与非阻塞赋值的不同 阻塞赋值: = 非阻塞赋值:<= 可以理解为:阻塞赋值有顺序,非阻塞赋值没有顺序,下面我们用实例来讲解: 阻塞赋值源码(截取) 解读:clk上升沿或者rst_n下降沿到来...
  • 阻塞赋值与非阻塞赋值的理解(非新手向) //code0 always@(posedgeclk) begin reg0<=in0+in1; reg1<=reg0+in2; end //code1 always@(posedgeclk) begin ...
  • 1.1 FPGA阻塞赋值与非阻塞赋值用法 1.1.1 本节目录 1)本节目录; 2)本节引言; 3)FPGA简介; 4)FPGA阻塞赋值与非阻塞赋值用法; 5)结束语。 1.1.2 本节引言 “不积跬步,无以至千里;不积小流,无以成...
  • Verilog阻塞赋值与非阻塞赋值

    万次阅读 多人点赞 2014-05-06 09:05:14
    1.阻塞赋值与非阻塞赋值; 2.代码测试; 3.组合逻辑电路和时序逻辑电路。   阻塞赋值与非阻塞赋值: 1.阻塞赋值“=”(组合逻辑电路),非阻塞赋值“”(时序逻辑电路); 2.Verilog模块编程的8个原则: (1)...
  • 实验目的:掌握阻塞赋值与非阻塞赋值的区别 1.实验原理: 在Verilog HDL语言中,信号有两种赋值方式:非阻塞赋值和阻塞赋值; 其中有两个要点: 1.在描述组合逻辑的always块中用阻塞赋值,则综合成组合逻辑的电路...
  • 阻塞赋值与非阻塞赋值详解,是我见过的最详细的解释,有代码和例子,很实用。
  • 阻塞赋值与非阻塞赋值的再分析

    千次阅读 2017-08-25 14:27:10
    在Verilog HDL设计中,经常会遇到阻塞赋值与非阻塞赋值,这是学习逻辑设计时最基础的知识点。设计者经常会在书中看到一些建议:什么时候该用阻塞赋值,什么情况下使用非阻塞赋值。可是,如果仅仅按照这样的设计推荐...
  • 5. 阻塞赋值与非阻塞赋值 1 Verilog 代码 2 原理图 3 Modelsim仿真 阻塞赋值(block): “=”,语句执行有先后顺序,串行执行 非阻塞赋值(unblock):"<=",语句执行无先后顺序,并行执行 注意:不要再同一个always...
  • 阻塞赋值的执行可以认为是只有一个步骤的操作,即计算RHS并更新LHS,且不允许其他语句的干扰。

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 370
精华内容 148
关键字:

阻塞赋值与非阻塞赋值