(筆記) 如何將值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
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
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
模擬結果
這是最常見,也最直覺的寫法。一個D-FF會delay 1個clk,要delay 3個clk,所以就用3個D-FF,經過模擬,q也的確delay了3個clk。
Method 2:
delay_3t.v / Verilog
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長怎樣?
在合成之後,Quartus II僅用了一個3 bit的D-FF,將output q再接回d 2次,而達成delay 3個clk,並不是如我們原本所想的,使用了3個D-FF串聯。我們將這種硬體思維,再次用Verilog表達。
Method 3:
使用for
delay_nt.v / Verilog
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. BHASKER的Verilog HDL Primer與吳戈的Verilog HDL與數字系統設計簡明教程這兩本書都用這種寫法。不過使用for仍不是最精簡的寫法。
Method 4:
delay_nt.v / Verilog
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打開做驗證。
完整程式碼下載
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)