宣告模組後,我們就可以開始使用它了!但是在那之前我們先來回顧之前提到的內建模組吧!
我們曾經說過 Verilog 提供了邏輯閘的模組,例如:and, or, xor 等,但是要特別注意的是這些邏輯閘都是執行位元運算,可以理解為下面的定義:
module and (output f, input a, b);
那要怎麼使用呢?可以用物件導向的思考模式來處理,模組其實就是 class,而現在要做的就是建立一個物件 (instantiate) 。首先我們要先決定使用哪一個模組,再來,我們要為這個物件取一個名字,最後依照模組的端口變數放入對應的參數。
給一個簡單的例子吧!假設我們要完成 a = b & c | d
,該如何實現呢?
wire a, b, c, d, temp; // 5 條線路
and A1(temp, b, c); // temp = b & c
or O1(a, temp, d); // a = temp | d = (b & c) | d
我們試試用剛才學到的觀念來完善 HalfAdder
這個模組吧!
上一篇文章,我們已經把模組的端口都指定完畢,現在我們把他的內部行為也一併處理。
如果尚未清楚 Half Adder 的概念,可以參考一下這張電路圖 (來源:維基百科)
可以試著根據電路圖寫出程式碼!
module HalfAdder (
input A, B,
output Cout, Sum
);
xor G0(Sum, A, B);
and G1(Cout, A, B);
endmodule
如果我們想要使用自製模組,那我們必須要先定義一個更高層次的模組。
什麼意思啊?假設我們要使用半加器 (Half Adder) ,那麼可能會先定義全加器 (Full Adder) 模組,並在全加器模組中使用。我們可以從下方的電路圖來了解全加器和半加器的關係。(圖片來源:tutorialspoint)
其實,一個全加器可以用兩個半加器搭配一個 or gate 來完成,我們用 Verilog 來試試看吧!
module FullAdder (
input A, B, Cin,
output Cout, Sum
);
wire Cout1, Sum1, Cout2;
HalfAdder HA1(A, B, Cout1, Sum1); // 使用 Half Adder 模組
HalfAdder HA2(AxorB, Cin, Cout2, Sum); // 使用 Half Adder 模組
or G1(Cout, Cout1, Cout2); // 使用 or-gate 模組
endmodule
除了用 Gate-Level Modeling 來實作全加器,也可以使用 Dataflow Modeling 的觀念來完成。大致的過程是
module FullAdder (
input A, B, Cin,
output Cout, Sum
);
assign Sum = A ^ B ^ Cin;
assign Cout = (A & B) | (A & Cin) | (B & Cin);
endmodule