Verilog中genvar 和 generate的使用

LilMonsterOvO發表於2024-11-14

1. genvargenerate 的作用

  • genvar 是一種特殊的資料型別,用於在 generate 語句塊中定義 迴圈變數。與普通變數不同的是,genvar 只能用於 generate 語句中,並且只能用於生成時刻(編譯時)進行評估,而非模擬時。
  • generate 塊用於生成硬體邏輯。它允許使用 for 迴圈、if 條件語句等來建立多個例項或連線邏輯。

2. 基本用法示例

假設我們有一個任務需要反轉一個 100 位的輸入向量(你之前的例子)。我們可以使用 genvargenerate 來實現:

module top_module(
    input [99:0] in,
    output [99:0] out
);
    genvar i;
    generate
        // 使用 generate-for 迴圈反轉輸入向量
        for (i = 0; i < 100; i = i + 1) begin
            assign out[i] = in[99 - i];
        end
    endgenerate
endmodule

3. 程式碼解釋

  • genvar i;:定義一個生成變數 i,它將用於 generate 塊中的 for 迴圈。
  • generate ... endgenerate:定義一個 generate 語句塊,裡面包含一個 for 迴圈,用於生成多個賦值語句。
  • for (i = 0; i < 100; i = i + 1):迴圈 100 次,將輸入向量 in 的每一位反轉後賦值給輸出向量 out
    • i = 0 時,out[0] = in[99]
    • i = 1 時,out[1] = in[98]
    • 以此類推,直到 i = 99

4. generate 塊的特點

  • 編譯時執行generate 塊在編譯時被執行,因此生成的硬體邏輯在綜合時被展開,而不是在模擬時動態執行。這意味著它更類似於模板展開,而不是執行時迴圈。
  • 可用於條件生成:除了 for 迴圈,還可以使用 ifcase 等條件語句來生成模組。例如:
    generate
        if (WIDTH == 8) begin
            // 生成 8 位的邏輯
        end else begin
            // 生成其他寬度的邏輯
        end
    endgenerate
    

5. 示例:使用 generate 實現多個暫存器

假設我們要例項化 8 個 D 觸發器,可以使用 generate 塊簡化程式碼:

module d_flip_flop(
    input clk,
    input d,
    output reg q
);
    always @(posedge clk)
        q <= d;
endmodule

module top_module(
    input clk,
    input [7:0] d,
    output [7:0] q
);
    genvar i;
    generate
        for (i = 0; i < 8; i = i + 1) begin
            d_flip_flop dff (
                .clk(clk),
                .d(d[i]),
                .q(q[i])
            );
        end
    endgenerate
endmodule

6. 總結

  • genvar 用於生成塊中的迴圈控制變數,只能用於生成時刻(編譯時)評估。
  • generate ... endgenerate 用於自動生成重複的硬體邏輯。
  • 透過 generate 語句,可以減少手動展開重複邏輯的程式碼量,提高程式碼的可讀性和可維護性。

7.補充

有些編譯器會有錯誤提示:

Error (10644): Verilog HDL error at top_module.v(8): this block requires a name

解釋:

這個錯誤通常意味著 generate 塊中的 for 迴圈塊沒有被正確命名。在 Verilog 中,當你在 generate 語句中使用 for 迴圈時,每個生成的塊需要有一個名稱,否則會導致編譯器報錯。

在之前的程式碼中,我們的 for 迴圈沒有為生成的塊指定名稱。這在某些 Verilog 編譯器中是可以接受的,但在更嚴格的工具(如 Quartus)中則會報錯。

解決方法:

for 迴圈塊一個名稱即可。例如:

module top_module(
    input [99:0] in,
    output [99:0] out
);
    genvar i;
    generate
        // 給 for 迴圈生成的塊加一個名稱,例如 "bit_reverse"
        for (i = 0; i < 100; i = i + 1) begin : bit_reverse
            assign out[i] = in[99 - i];
        end
    endgenerate
endmodule

相關文章