Thursday, June 30, 2016

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

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

 

  1. module func1(clk, Input1, Output1, Output2);
  2.  
  3. input clk;
  4. input [15:0] Input1;
  5. output [15:0] Output1, Output2;
  6.  
  7. always@(posedge clk)
  8. begin
  9. Output1 <= Input1 + 1;
  10. Output2 <= Output1;
  11. end
  12.  
  13. endmodule

出現的錯誤訊息如下:

  1.         Output1 <= Input1 + 1;
  2.  
  3.              |
  4.  
  5. ncvlog: *E,WANOTL (func1.v,10|8): a net is not a legal lvalue in this context [9.3.1(IEEE)].
  6.  
  7.         Output2 <= Output1;
  8.  
  9.              |
  10.  
  11. ncvlog: *E,WANOTL (func1.v,11|8): a net is not a legal lvalue in this context [9.3.1(IEEE)].
  12.  
  13.     module worklib.func1:v
  14.  
  15.         errors: 2, warnings: 0


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

  1. module func1( clk, Input1, Output1, Output2 );
  2.  
  3.     input        clk;
  4.     input [15:0] Input1;
  5.     output [15:0] Output1, Output2;
  6.     reg    [15:0] Output1, Output2;
  7.    
  8.     always @ (posedge clk)
  9.     begin
  10.         Output1    <= Input1+1;
  11.         Output2    <= Output1;
  12.     end
  13.  
  14. endmodule

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


  1. `define    cycle    4
  2. module    func1_test();
  3.  
  4.     reg [15:0] a;
  5.     wire [15:0] b, c;
  6.     reg   clk;
  7.  
  8.     initial    clk    = 0;
  9.     always #(`cycle/2)    clk = ~clk;
  10.  
  11.     func1 func1_te( .clk(clk), .Input1(a), .Output1(b), .Output2(c) );
  12.  
  13.     initial begin
  14.  
  15.         @(posedge clk)
  16.         a = 16'b0000000000000001;       
  17.  
  18.         @(posedge clk)
  19.         a = 16'b0000000000000010;
  20.  
  21.         @(posedge clk)
  22.         a = 16'b0000000000000011;
  23.  
  24.         @(posedge clk)
  25.         a = 16'b0000000000000100;
  26.  
  27.         @(posedge clk)
  28.         a = 16'b0000000000001000;
  29.  
  30.         #100    $finish;
  31.  
  32.     end
  33.  
  34.     initial    begin
  35.     $monitor($time, " a=%d, b=%d, c=%d", a, b, c);
  36.     end
  37.  
  38.     initial    begin
  39.     $fsdbDumpfile("func1.fsdb");
  40.     $fsdbDumpvars;
  41.     end
  42.  
  43. 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。為了確認這件事情,將程式改成底下的寫法,並觀察結果:


  1. module func1( clk, Input1, Output1, Output2 );
  2.  
  3.     input           clk;
  4.     input   [15:0]  Input1;
  5.     output  [15:0]  Output1, Output2;
  6.     reg     [15:0]  wInput;
  7.     reg     [15:0]  Output1, Output2;
  8.  
  9.     always @ (posedge clk)
  10.     begin
  11.         wInput  <= Input1;
  12.         Output1 <= wInput+1;
  13.         Output2 <= Output1;
  14.     end
  15.  
  16. endmodule
  17.  

額外宣告了一個 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.

No comments:

Post a Comment

熱門文章