(筆記) 如何將值delay n個clock? (SOC) (Verilog)

Abstract
在實務上為了與其他信號同步,常會故意delay幾個clk,本文整理出幾種常見的coding style。

Introduction
使用環境:NC-Verilog 5.4 + Debussy 5.4 + Quartus II 9.0

為什麼需要將值delay n的clk呢?比如說我想運算A+B,目前這個clk A已經到了,但B必須delay 3個clk之後才會到,為了運算A+B,勢必使用shift register將A delay 3個clk之後,才能與B同步,所以希望先做出delay 3個clk的功能,進而實作出delay n個clk。

Method 1:
delay_3t.v / Verilog
 

1 /* 
2 (C) OOMusou 2009 http://oomusou.cnblogs.com
3 
4 Filename    : delay_3t.v
5 Compiler    : NC-Verilog 5.4
6 Description : delay 3t method 1
7 Release     : 06/15/2009 1.0
8 */
9 
10 module delay_3t (
11   clk,
12   rst_n,
13   d,
14   q
15 );
16 
17 input  clk;
18 input  rst_n;
19 input  d;
20 output q;
21 
22 reg d_dly_1t;
23 reg d_dly_2t;
24 reg d_dly_3t;
25 
26 assign q = d_dly_3t;
27 
28 always@(posedge clk or negedge rst_n) begin
29   if (!rst_n) begin
30     d_dly_1t <= 0;
31     d_dly_2t <= 0;
32     d_dly_3t <= 0;
33   end
34   else begin
35     d_dly_1t <= d;
36     d_dly_2t <= d_dly_1t;
37     d_dly_3t <= d_dly_2t;
38   end
39 end
40 
41 endmodule


Testbench
delay_3t_tb.v / Verilog

1 /* 
2 (C) OOMusou 2009 http://oomusou.cnblogs.com
3 
4 Filename    : delay_3t_tb.v
5 Compiler    : NC-Verilog 5.4
6 Description : delay 3t method 1
7 Release     : 06/15/2009 1.0
8 */
9 
10 `include "delay_3t.v"
11 
12 module delay_3t_tb;
13 
14 reg clk;
15 reg rst_n;
16 reg d;
17 wire q;
18 
19 delay_3t u0 (
20   .clk(clk),
21   .rst_n(rst_n),
22   .d(d),
23   .q(q)
24 );
25 
26 initial begin
27   $fsdbDumpfile("delay_3t.fsdb");
28   $fsdbDumpvars(0, delay_3t_tb);
29 end
30 
31 // clk
32 initial begin
33   clk = 0;
34   forever #10 clk = ~clk;
35 end
36 
37 initial begin
38   rst_n = 0;
39   d = 0;
40   #20;
41   rst_n = 1;
42   #11;
43   d = 1;
44   #20;
45   d = 0;
46   #500;
47   $finish;
48 end
49 
50 endmodule


模擬結果

del00

這是最常見,也最直覺的寫法。一個D-FF會delay 1個clk,要delay 3個clk,所以就用3個D-FF,經過模擬,q也的確delay了3個clk。

Method 2:
delay_3t.v / Verilog

1 /* 
2 (C) OOMusou 2009 http://oomusou.cnblogs.com
3 
4 Filename    : delay_3t.v
5 Compiler    : NC-Verilog 5.4
6 Description : delay 3t method 2
7 Release     : 06/15/2009 1.0
8 */
9 
10 module delay_3t (
11   clk,
12   rst_n,
13   d,
14   q
15 );
16 
17 input  clk;
18 input  rst_n;
19 input  d;
20 output q;
21 
22 reg d_dly_1t;
23 reg d_dly_2t;
24 reg d_dly_3t;
25 
26 assign q = d_dly_3t;
27 
28 always@(posedge clk or negedge rst_n) begin
29   if (!rst_n)
30     {d_dly_3t, d_dly_2t, d_dly_1t}  <= 0;
31   else
32     {d_dly_3t, d_dly_2t, d_dly_1t} <= {d_dly_2t, d_dly_1t, d};
33 end
34 
35 endmodule


Testbench與模擬的波型圖與Method 1完全一樣,所以加以省略。這種寫法在DE2的範例也曾經出現過,思維仍是3個D-FF,只是寫法比較tricky,利用了Verilog特有的{}語法,一行就解決,比Method 1更精簡。

不過這兩個寫法都有個問題,若要delay 10個clk,就得宣告10個reg,程式相當冗長,是否有更簡單的寫法呢?

我們知道Quartus II最後都會將我們寫的RTL code加以最佳化,來看看經過Quartus II編譯後,RTL Viewer長怎樣?

delay01

在合成之後,Quartus II僅用了一個3 bit的D-FF,將output q再接回d 2次,而達成delay 3個clk,並不是如我們原本所想的,使用了3個D-FF串聯。我們將這種硬體思維,再次用Verilog表達。

Method 3:
使用for

delay_nt.v / Verilog

1 /* 
2 (C) OOMusou 2009 http://oomusou.cnblogs.com
3 
4 Filename    : delay_nt.v
5 Compiler    : NC-Verilog 5.4
6 Description : delay 3t method 3
7 Release     : 06/15/2009 1.0
8 */
9 
10 module delay_nt (
11   clk,
12   rst_n,
13   d,
14   q
15 );
16 
17 parameter n = 1;
18 
19 input  clk;
20 input  rst_n;
21 input  d;
22 output q;
23 
24 reg [n-1:0] r;
25 
26 assign q = r[n-1];
27 
28 integer i;
29 
30 always@(posedge clk or negedge rst_n) begin
31   if (!rst_n)
32     r <= 0;
33   else begin
34     for(i=0; i<n-1; i=i+1)
35       r[i+1] <= r[i];
36      
37     r[0] <= d;
38   end
39 end
40 
41 endmodule


既然要做個通用的shift register,很直覺的會想到用for,這種寫法在很多書上都曾看過,就我印象中,在J. BHASKERVerilog HDL Primer吳戈Verilog HDL與數字系統設計簡明教程這兩本書都用這種寫法。不過使用for仍不是最精簡的寫法。

Method 4:
delay_nt.v / Verilog

1 /* 
2 (C) OOMusou 2009 http://oomusou.cnblogs.com
3 
4 Filename    : delay_nt.v
5 Compiler    : NC-Verilog 5.4
6 Description : delay 3t method 4
7 Release     : 06/15/2009 1.0
8 */
9 
10 module delay_nt (
11   clk,
12   rst_n,
13   d,
14   q
15 );
16 
17 parameter n = 3;
18 
19 input  clk;
20 input  rst_n;
21 input  d;
22 output q;
23 
24 reg [n-1:0] r;
25 
26 assign q = r[n-1];
27 
28 always@(posedge clk or negedge rst_n) begin
29   if (!rst_n)
30     r <= 0;
31   else
32     r <= {r, d}; 
33 end
34 
35 endmodule


{}寫法是Verilog的獨門絕技,這樣就不再需要for,這也是為什麼Verilog寧願從C語言搶走{}換來begin, end,因為{}這種合併的寫法非常的好用。Testbench與模擬波型圖也與Method 1與Method 2一樣,再次省略。這種寫法使用了parameter,無論要delay幾個clk,只需修改n即可,而且與Quartus II最佳化後的硬體一樣,我們再次將編譯過的RTL Viewer打開做驗證。

delay02

完整程式碼下載
delay_3t.7z (Method 1)
delay_3t2.7z (Method 2)
delay_nt2.7z (Method 3)
delay_nt.7z (Method 4)

Conclusion
這4種寫法最後合出來的硬體都一樣,表示現在的合成器都夠聰明,差別只是在哪種coding style較好,將來比較好維護。另外也是開開眼界,若將來閱讀其他人的code,馬上就知道對方想表達的意思。

See Also
(原創) 如何將parallel轉成serial?如何將serial轉成parallel? (SOC) (Verilog)

(原創) 如何實現簡易的數位濾波器? (SOC) (Verilog)

posted on 2009-06-15 20:45  真 OO无双  阅读(39360)  评论(13编辑  收藏  举报

导航