Generate 是個很強大的語法。
在寫 Verilog 時,我最討厭的狀況是:(以 Pseudocode 表示)
if (cond == True)
ic1 a(...);
else
ic2 b(...);
簡單來說,我們會根據不同的狀況實體化不同的模組 (i.e. ic1, ic2) ,但是 if, else 必須被放置在 initial, always blocks 中。不只如此,initial, always blocks 內部是不能進行模組實體化的。因此上述的 Pseudocode 在 Verilog 中是不可行的。當然我們可以透過組合電路歸納出條件式的關係,但是那會相當麻煩。Generate 的其中一項功能就是解決上述 Pseudocode 所表達的事情!
為什麽 Generate 可以達成原本不可能的事情?
程式真正被處理的時間有兩個,一個就是大家理想狀況下的程式執行,另一種是執行前的預先處理。Generate 就是在執行前被預先處理的。而在執行開始時,所有電路元件都會被設計與置放完成,這樣就不會影響到原本的行為了!
Generate 共包含 3 種模式:
Conditional 就是「條件的」,用 C 語言的語法來說就是 if, else。
在 Verilog HDL: A Guide to Digital Design and Synthesis 這本書中提到了一個很實用的例子,想藉由這個機會和大家分享。這份程式碼的大意是說題目給了兩個數字,如果其中一個數子的位元數少於 8 位元,就使用 CLA 乘法器,否則就使用 Tree 乘法器。為什麼說實用?因為使用不同乘法器會有不同的效能,如果數字很大,但是使用了沒有被優化過的乘法器,後果可想而知。因此我們會先透過 Generate Conditional 來判定該時作何種硬體。
module multiplier (product, a0, a1);
parameter a0_width = 8; // 8-bit bus by default
parameter a1_width = 8; // 8-bit bus by default
localparam product_width = a0_width + a1_width;
output [product_width -1:0] product;
input [a0_width-1:0] a0;
input [a1_width-1:0] a1;
generate
if (a0_width <8) || (a1_width < 8)
cla_multiplier #(a0_width, a1_width) m0 (product, a0, a1);
else
tree_multiplier #(a0_width, a1_width) m0 (product, a0, a1);
endgenerate //end of the generate block
endmodule
程式碼中除了使用 generate ,還提到 parameter, localparam (這部分我們會在之後的章節提及) 等。透過這種組合,我們的電路更加的完善,因為電路變得可以透過賦予參數來產生不同的樣貌,而不是一開始就需要指定的。
補充: 不知道大家會不會好奇什麼是 Tree 乘法器?有興趣的同學可以參考 維基百科。
Wallace Tree 是一種加速二進位乘法的硬體設計,他最主要的原理就是使用半加器和全加器來產生 Sum, Carry 。Wallace Tree 也可以視為 3 to 2 compressor ,因為在過程中,我們每此都取 3 行結果進行處理,處理後會得到 2 行,分別為 Sum Row, Carry Row 。如此不斷下去,我們可以得到最終的乘積。
既然 if, else 可以搭配 generate 來使用,case 也可以這麼做!
假設我們有多種計數器,但是根據不同情況,我們使用不同種計數器,範例如下:
generate
case (N)
0: johnson j(...);
1: mod5 m1(...);
2: mod6 m2(...);
...
default: ring r(...);
endcase
endgenerate
還有一種狀況是我們必須要重複實體化一樣的模組許多次,與 if, else 相同的是, for loop 內部無法實體化模組,因為他們存在於 initial, always loop 之中。因此我們會借用 generate 來完成這件事。
舉例來說,我們實作 Ripple Carry Adder 就可以透過這種方式來執行。大致上可以歸納兩個優點:
genvar i;
generate for (i = 0; i < N; i++) begin
Fadder f0(...);
end
endgenerate