欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 6486|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

FPGA學(xué)習(xí)-例解阻塞賦值與非阻塞賦值

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:108531 發(fā)表于 2016-3-12 22:34 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
據(jù)說阻塞賦值和非阻塞賦值是Verilog 語言中最難理解的知識(shí)點(diǎn)之一,我也覺得,從網(wǎng)上翻閱了資料,也看過一些視頻。

以下從兩個(gè)典型的例子以及多個(gè)角度去分析得到與驗(yàn)證阻塞賦值與非阻塞賦值的區(qū)別,以及各自的特點(diǎn)。
 
 

非阻塞賦值與阻塞賦值特性

1、非阻塞賦值的特性:

賦值語句的流程:

a)計(jì)算右邊的表達(dá)式得到結(jié)果

b)將結(jié)果賦值到左邊的變量

這個(gè)過程中允許來自任何其他Verilog語句的干擾,也就是說其他Verilog語句都可以在這個(gè)時(shí)候執(zhí)行。

2、阻塞賦值特性:

賦值語句的流程:

c)計(jì)算右邊的表達(dá)式得到結(jié)果

d)將結(jié)果賦值到左邊的變量

這個(gè)過程中不允許有來自任何其他Verilog語句的干擾,這就導(dǎo)致其他的Verilog語句會(huì)等待(阻塞)該賦值語句執(zhí)行完畢后才能被執(zhí)行,這就是阻塞的含義。

 

根據(jù)小梅哥視頻《07_例解阻塞賦值與非阻塞賦值》去分析

一、非阻塞賦值分析

1、非阻塞賦值源程序

/* 實(shí)驗(yàn)名稱:非阻塞賦值 */

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

 

從源碼中分析,根據(jù)非阻塞語句的特性, 假設(shè) a = 0,b = 1, c = 0;

當(dāng)rst_n為高時(shí),由于d<=a+b、out<=d+c; 是同時(shí)執(zhí)行,所以:

1、右邊表達(dá)式的結(jié)果:a + b = 0 + 1 = 1、d + c = 0 + 0 = 0

2、再將結(jié)果賦值給左邊: d = a + 1就等于 1,out = d + c 就等于 0

 

2、RTL視圖

 

    其實(shí)RTL視圖中也能看出來,假設(shè)a = 0,b = 1, c = 0; d寄存器為0,out寄存器為0 ;

那么當(dāng)一個(gè)時(shí)鐘周期到來:(以下兩步會(huì)同時(shí)執(zhí)行,即d與out寄存器會(huì)同時(shí)從加法器中取值)

1、Add0寄存器會(huì)將a(0) + b(1) = 1的值給d寄存器,d寄存器由0變?yōu)?

2、Add1寄存器會(huì)將d(0) + c(0) = 0的值給out寄存器,out寄存器仍是0

 

3、仿真測(cè)試源程序

`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 前一個(gè)時(shí)鐘周期的情況,由上圖可以看到,當(dāng)時(shí)鐘上升沿,采樣得到的 a、b、d、c都是等于0,而c是在時(shí)鐘上升沿之后才被拉高,所以要在下一個(gè)時(shí)鐘周期的上升沿才能采樣到c的狀態(tài),

如下圖:

然后我們?cè)偻罂纯础?span>

 

首先我們看到 01 與 01 直接夾著 0,那么01對(duì)應(yīng)的應(yīng)該是如下幾行的測(cè)試代碼,從代碼可以看到不應(yīng)該有00的存在。

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

#(`clock_period * 200);

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

#(`clock_period * 200);

因?yàn)閏變?yōu)?,b變?yōu)?是在時(shí)鐘周期的上升沿之后才變化這里暫時(shí)不考慮是在上升沿或下降沿時(shí)變化

而out和d的狀態(tài)因?yàn)檫^程中需要采樣和賦值操作,會(huì)有一個(gè)邏輯延遲的現(xiàn)象,也就是說也是在時(shí)鐘上升沿之后才會(huì)變化。以下為后仿真的波形圖,根據(jù)接近實(shí)際狀況

 

即圖中A上升沿時(shí):(以下兩步的采樣是在同一個(gè)時(shí)鐘上升沿同時(shí)進(jìn)行)

1、d的狀態(tài):舊狀態(tài)是0,經(jīng)過以下操作新的狀態(tài)是0

同時(shí)采樣a的狀態(tài)得到是0b的狀態(tài)得到的是0。所以d的狀態(tài)變?yōu)?

2、out的狀態(tài):舊狀態(tài)是1,經(jīng)過以下操作新的狀態(tài)變?yōu)?

同時(shí)到d是0c的狀態(tài)得到的是1,所以導(dǎo)致out變?yōu)?。

    3、在時(shí)鐘為穩(wěn)定電平期間c變?yōu)?,b變?yōu)?,即在上升沿之后

 

那么到了B上升沿時(shí)(以下兩步的采樣是在同一個(gè)時(shí)鐘上升沿同時(shí)進(jìn)行)

1、d的狀態(tài):舊狀態(tài)是0,經(jīng)過以下操作新的狀態(tài)是1

同時(shí)采樣a的狀態(tài)得到是0, b的狀態(tài)得到的是1。所以d的狀態(tài)變?yōu)?

2、out的狀態(tài):舊狀態(tài)是1,經(jīng)過以下操作新的狀態(tài)變?yōu)?

同時(shí)采樣到d是0,c的狀態(tài)得到的是0,所以導(dǎo)致out變?yōu)?。

 

當(dāng)?shù)紺上升沿的時(shí):(以下兩步的采樣是在同一個(gè)時(shí)鐘上升沿同時(shí)進(jìn)行)

1、d的狀態(tài):舊狀態(tài)是1,經(jīng)過以下操作新的狀態(tài)是1

同時(shí)采樣a的狀態(tài)得到是0b的狀態(tài)得到的是1。所以d的狀態(tài)變?yōu)?

2、out的狀態(tài):舊狀態(tài)是0,經(jīng)過以下操作新的狀態(tài)變?yōu)?

同時(shí)采樣到d是1c的狀態(tài)得到的是0,所以導(dǎo)致out變?yōu)?。

 

6、解決出現(xiàn)0的情況。

    分析原因:

從RTL視圖中可以看到是因?yàn)槎嗔藥讉(gè)d寄存器導(dǎo)致out寄存器慢了一個(gè)時(shí)鐘。

    從波形視圖中可以看到也是因?yàn)槎嗔薲,導(dǎo)致out寄存器出現(xiàn)了0狀態(tài)。

    結(jié)論:

將d去掉即可,以后寫程序過程中盡量不要采用中間變量,避免出現(xiàn)多余的寄存器出現(xiàn),導(dǎo)致不同步。

 

    源程序如下:

    `timescale 1ns/1ns

/* 實(shí)驗(yàn)名稱:非阻塞賦值 */

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視圖:(從下圖可以看到,來一個(gè)時(shí)鐘周期,那么out直接就取Add0和Add1的值)

 

    波形圖:(下圖比較小,可以對(duì)比上面的波形圖)

 

二、阻塞賦值分析

1、源程序(為了更加清晰的理解,我修改了視頻作者的源碼)

`timescale 1ns/1ns

/* 實(shí)驗(yàn)名稱:非阻塞賦值 */

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;        // 這個(gè)是用來指示當(dāng)前執(zhí)行的位置

   

    always@(posedge clk or negedge rst_n)

        if(!rst_n)

            out = 2'b0;

        else begin

            d = a + b;

            run =#1 1;    // 準(zhǔn)備執(zhí)行out賦值時(shí)

            out = d + c;

            run =#1 0;    // 執(zhí)行out賦值后

        end

 

endmodule

 

從源碼中分析,根據(jù)阻塞語句的特性, 假設(shè) a = 0,b = 1, c = 0;

當(dāng)rst_n為高時(shí),由于d=a+b、out=d+c; 是順序執(zhí)行,所以:

1、先執(zhí)行d = a + b = 0 + 1 = 1

2、在執(zhí)行:out = d + c = 1 + 0 = 1;

 

2、RTL視圖(沒看錯(cuò),就和去掉了d寄存器的非阻塞賦值代碼生成的電路一樣)

    這里就能看出與非阻塞賦值的不同之處,此處不再解釋。

 

3、仿真測(cè)試程序   

與非阻塞仿真測(cè)試程序一樣,略。

 

4、波形圖

 

5、波形圖分析

 

根據(jù)代碼我們知道run信號(hào)是執(zhí)行完d = a + b 之后為高電平,執(zhí)行完 out = d + c 為低電平。

通過run信號(hào)知道,每次都是在out變化之后才出現(xiàn)低電平。因?yàn)槿绻峭瑫r(shí)執(zhí)行的話,速度非常快,由于run原先就是低電平,變?yōu)楦唠娖胶妥優(yōu)榈碗娖蕉际茄訒r(shí)1ns,也就是說同時(shí)執(zhí)行1ns之后run依然會(huì)是低電平,如下圖,同樣的延時(shí),改為非阻塞的方式,out一直為低。

 

A時(shí)鐘上升沿到來:(以下三個(gè)步驟為順序執(zhí)行)

    1、d的狀態(tài):當(dāng)前狀態(tài)0,經(jīng)過采樣,新的狀態(tài)更新為0

        同時(shí)采樣a的狀態(tài)為0 b的狀態(tài)為0,d = a + b = 0 + 0 = 0;

    2、run信號(hào):

        被拉高

    3、out的狀態(tài):當(dāng)前狀態(tài)0,經(jīng)過采樣,新的狀態(tài)更新為0

        同時(shí)采樣d的狀態(tài)0、c的狀態(tài)為0,out = d + c = 0 + 0 = 0;

4、run信號(hào):

被拉低

 

B時(shí)鐘上升沿到來:(以下三個(gè)步驟為順序執(zhí)行)

    1、d的狀態(tài):當(dāng)前狀態(tài)0,經(jīng)過采樣,新的狀態(tài)更新為0

        同時(shí)采樣a的狀態(tài)為0、 b的狀態(tài)為0,d = a + b = 0 + 0 = 0;

    2、run信號(hào):

        被拉高

    3、out的狀態(tài):當(dāng)前狀態(tài)0,經(jīng)過采樣,新的狀態(tài)更新為1

        同時(shí)采樣d的狀態(tài)0、c的狀態(tài)為1,out = d + c = 0 + 1 = 1;

4、run信號(hào):

被拉低

 

C時(shí)鐘上升沿到來:(以下三個(gè)步驟為順序執(zhí)行)

    1、d的狀態(tài):當(dāng)前狀態(tài)0,經(jīng)過采樣,新的狀態(tài)更新為0

        同時(shí)采樣a的狀態(tài)為0、 b的狀態(tài)為0,d = a + b = 0 + 0 = 0;

    2、run信號(hào):

        被拉高

    3、out的狀態(tài):當(dāng)前狀態(tài)1,經(jīng)過采樣,新的狀態(tài)更新為1

        同時(shí)采樣d的狀態(tài)0、c的狀態(tài)為1,out = d + c = 0 + 1 = 1;

4、run信號(hào):

被拉低

 

通過以上步驟可以發(fā)現(xiàn),執(zhí)行的時(shí)間、采樣的時(shí)間不一樣,會(huì)導(dǎo)致不一樣的結(jié)果。

 

 

另外一個(gè)實(shí)驗(yàn):根據(jù)網(wǎng)上的一篇文章的例子,然后再通過看波形的方式去驗(yàn)證。

http://blog.163.com/xiaoting_hu/blog/static/50464772201361162838112/

 

 

一、非阻塞賦值分析

1、非阻塞賦值例程

/* 實(shí)驗(yàn)名稱:阻塞與非阻塞賦值差異實(shí)驗(yàn)

 * 程序功能:阻塞賦值 - 觀看 RTL-View 以及波形 */

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

 

    output reg o_y1, o_y2;

    input wire i_clk, i_rst;

   

    //異步復(fù)位 alwaysA

    always@(posedge i_clk or negedge i_rst)

        if(!i_rst)    

o_y1 <= 0;        // 低電平復(fù)位

        else        

o_y1 <= o_y2;

   

    //異步復(fù)位 alwaysB

    always@(posedge i_clk or negedge i_rst)

        if(!i_rst)   

o_y2 <= 1;        // 低電平復(fù)位

        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;                    // 復(fù)位

        #(`clock_period * 5);

        rst = 1'b1;                    // 開始執(zhí)行

        #(`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、波形分析

//異步復(fù)位 alwaysA

    always@(posedge i_clk or negedge i_rst)

        if(!i_rst)    

o_y1 <= 0;        // 低電平復(fù)位

        else        

o_y1 <= o_y2;

   

//異步復(fù)位 alwaysB

    always@(posedge i_clk or negedge i_rst)

        if(!i_rst)   

o_y2 <= 1;        // 低電平復(fù)位

        else       

o_y2 <= o_y1;

 

當(dāng) i_rst == 0 :o_y1 被賦值為 0, o_y2 被賦值為 1,由于非阻塞賦值特性,所以無先后順序

當(dāng) i_rst == 1 :由于兩個(gè) always 塊會(huì)被同時(shí)執(zhí)行。即 fpga 會(huì)在同一個(gè)時(shí)鐘上升沿進(jìn)行采樣,

第一個(gè)時(shí)鐘周期:

alwaysA 會(huì)對(duì) o_y2 采樣得到為高電平,所以給 o_y1 賦值為高電平。

alwaysB 會(huì)對(duì) o_y1 采樣得到為低電平,所以給 o_y2 賦值為低電平。

第二個(gè)時(shí)鐘周期:

alwaysA 會(huì)對(duì) o_y2 采樣,因?yàn)樵诘谝粋(gè)周期中 o_y2 因 o_y1 而賦值為低電平,所以采樣得到為低電平,所以給 o_y1 賦值為低電平。

alwaysB 會(huì)對(duì) o_y1 采樣,因?yàn)樵诘谝粋(gè)周期中 o_y1 因 o_y2 而賦值為高電平,所以采樣得到為高電平,所以給 o_y2 賦值為高電平。

之后的時(shí)鐘周期都是根據(jù)這樣的規(guī)律進(jìn)行變化,所以我們看到的波形 o_y1、o_y2 是相反狀態(tài)。

 

阻塞賦值分析

1、阻塞賦值源程序

/* 實(shí)驗(yàn)名稱:阻塞與非阻塞賦值差異實(shí)驗(yàn)

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

 */

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

 

    output reg o_y1, o_y2;

    input wire i_clk, i_rst;

   

    //異步復(fù)位

    always@(posedge i_clk or negedge i_rst)

        if(!i_rst)    

            o_y1 = 0;        // 低電平復(fù)位

        else        

            o_y1 = o_y2;

 

    //異步復(fù)位

    always@(posedge i_clk or negedge i_rst)

        if(!i_rst)   

            o_y2 = 1;        // 低電平復(fù)位

        else       

            o_y2 = o_y1;

       

endmodule

 

2、RTL 視圖(居然和阻塞一樣的 RTL 視圖)

3、仿真源程序

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

3、波形圖

 

4、波形分析

//異步復(fù)位alwaysA

    always@(posedge i_clk or negedge i_rst)

        if(!i_rst)    

            o_y1 = 0;        // 低電平復(fù)位

        else        

            o_y1 = o_y2;

   

    //異步復(fù)位 alwaysB

    always@(posedge i_clk or negedge i_rst)

        if(!i_rst)   

            o_y2 = 1;        // 低電平復(fù)位

        else       

            o_y2 = o_y1;

 

當(dāng) i_rst == 0 :o_y1 被賦值為 0, o_y2 被賦值為 1, 由于阻塞賦值特性,所以有先后順序,但無法確定誰先誰后。

當(dāng) i_rst == 1由于阻塞賦值的特性,在執(zhí)行阻塞賦值語句時(shí)其他語句均不能得到執(zhí)行。由于兩個(gè) always 塊會(huì)被同時(shí)執(zhí)行,而且 o_y1 和 o_y2 的取值是互相影響,所以 o_y1、o_y2 值取決于那個(gè) always 塊的賦值語句先執(zhí)行。從波形來看,明顯是 alwaysA 最新得到執(zhí)行。

第一個(gè)時(shí)鐘周期:

alwaysA 會(huì)對(duì) o_y2 采樣得到為高電平,所以給 o_y1 賦值為高電平。

alwaysB 會(huì)對(duì) o_y1 采樣因在 alwaysA 程序塊 o_y1 因 o_y2 而賦值為高電平,所以給 o_y2 賦值為高電平。

 

第二個(gè)時(shí)鐘周期:

alwaysA 會(huì)對(duì) o_y2 采樣,因?yàn)樵诘?/span>個(gè)周期中 o_y2 因 o_y1 而賦值為電平,所以采樣得到為電平,所以給 o_y1 賦值為電平。

alwaysB 會(huì)對(duì) o_y1 采樣,因在 alwaysA 程序塊 o_y1 因 o_y2 而賦值為高電平,所以給 o_y2 賦值為高電平。

 

也就是說 o_y1 = o_y2; o_y2 = o_y1; 是順序執(zhí)行的所以我們看到的波形 o_y1、o_y2 都是高電平狀態(tài).


最后附上非阻塞賦值的一個(gè)很有意思的例子。

 

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表