2016年6月30日 星期四

【學習】VERILOG 學習筆記:reg 宣告與延遲

這幾天為了測試  non-blocking 的用法,寫了底下的範例,卻發現 compiler 一直過不了。




module func1(clk, Input1, Output1, Output2);

    input         clk;
    input  [15:0] Input1;
    output [15:0] Output1, Output2;

    always@(posedge clk)
    begin
    
        Output1 <= Input1 + 1;
        Output2 <= Output1;
        
    end

endmodule

出現的錯誤訊息如下:

        Output1 <= Input1 + 1;

             |

ncvlog: *E,WANOTL (func1.v,10|8): a net is not a legal lvalue in this context [9.3.1(IEEE)].

        Output2 <= Output1;

             |

ncvlog: *E,WANOTL (func1.v,11|8): a net is not a legal lvalue in this context [9.3.1(IEEE)].

    module worklib.func1:v

        errors: 2, warnings: 0


一時之間毫無頭緒,只好找同事協助,後來才發現,在 always 裡面的 noblocking assignment 不能單單宣告為 output 屬性,需要賦予 reg 屬性,才可以正確動作,範例修正如下:

module func1( clk, Input1, Output1, Output2 );

    input           clk;
    input   [15:0]  Input1;
    output  [15:0]  Output1, Output2;
    reg     [15:0]  Output1, Output2;
    
    always @ (posedge clk)
    begin
        Output1    <= Input1+1;
        Output2    <= Output1;
    end

endmodule

修改後便可以正常 compiler 了,再寫個 test bench 去確認執行結果:


`define    cycle    4
module    func1_test();

    reg   [15:0]  a;
    wire  [15:0]  b, c;
    reg           clk;

    initial    clk    = 0;
    always #(`cycle/2)    clk = ~clk;

    func1  func1_te( .clk(clk), .Input1(a), .Output1(b), .Output2(c) );

    initial  begin

        @(posedge clk)
        a = 16'b0000000000000001;        

        @(posedge clk)
        a = 16'b0000000000000010;

        @(posedge clk)
        a = 16'b0000000000000011;

        @(posedge clk)
        a = 16'b0000000000000100;

        @(posedge clk)
        a = 16'b0000000000001000;

        #100    $finish;

    end

    initial    begin
    $monitor($time, " a=%d, b=%d, c=%d", a, b, c);
    end

    initial    begin
    $fsdbDumpfile("func1.fsdb");
    $fsdbDumpvars;
    end

endmodule

compiler 後將訊息打在螢幕,發現有趣的現象:

                   0 a=    x, b=    x, c=    x
                   2 a=    1, b=    2, c=    x
                   6 a=    2, b=    3, c=    2
                  10 a=    3, b=    4, c=    3
                  14 a=    4, b=    5, c=    4
                  18 a=    8, b=    9, c=    5
                  22 a=    8, b=    9, c=    9

變數 c 在 time 2 的時後,也就是第一次 clk 拉起時並沒有被賦值,而是延遲到了下次 clk rising 才會進行賦值,並賦予上個 clk 變數 b 的值,即變數 c 的賦值被延遲了一個 clock。為了確認這件事情,將程式改成底下的寫法,並觀察結果:


module func1( clk, Input1, Output1, Output2 );

    input           clk;
    input   [15:0]  Input1;
    output  [15:0]  Output1, Output2;
    reg     [15:0]  wInput;
    reg     [15:0]  Output1, Output2;

    always @ (posedge clk)
    begin
        wInput  <= Input1;
        Output1 <= wInput+1;
        Output2 <= Output1;
    end

endmodule


額外宣告了一個 reg wInput,並將 Input1 先賦予 wInput,發現:

                   0 a=    x, b=    x, c=    x
                   2 a=    1, b=    x, c=    x
                   6 a=    2, b=    2, c=    x
                  10 a=    3, b=    3, c=    2
                  14 a=    4, b=    4, c=    3
                  18 a=    8, b=    5, c=    4
                  22 a=    8, b=    9, c=    5
                  26 a=    8, b=    9, c=    9

變數 b 的賦直延遲了一個 clock 並且 c 延遲兩個 clock 後始有動作。

Taiwan is an independent country.

沒有留言:

張貼留言

熱門文章