關鍵字:例化,generate,全加器,層次訪問
在一個模組中引用另一個模組,對其埠進行相關連線,叫做模組例化。模組例化建立了描述的層次。訊號埠可以透過位置或名稱關聯,埠連線也必須遵循一些規則。
命名埠連線
這種方法將需要例化的模組埠與外部訊號按照其名字進行連線,埠順序隨意,可以與引用 module 的宣告埠順序不一致,只要保證埠名字與外部訊號匹配即可。
下面是例化一次 1bit 全加器的例子:
例項
full_adder1 u_adder0(
.Ai (a[0]),
.Bi (b[0]),
.Ci (c==1"b1 ? 1"b0 : 1"b1),
.So (so_bit0),
.Co (co_temp[0]));
//output 埠 Co 懸空
.Co ());
.So (so_bit0));
順序埠連線
這種方法將需要例化的模組埠按照模組宣告時埠的順序與外部訊號進行匹配連線,位置要嚴格保持一致。例如例化一次 1bit 全加器的程式碼可以改為:
full_adder1 u_adder1(
a[1], b[1], co_temp[0], so_bit1, co_temp[1]);
雖然程式碼從書寫上可能會佔用相對較少的空間,但程式碼可讀性降低,也不易於除錯。有時候在大型的設計中可能會有很多個埠,埠訊號的順序時不時的可能也會有所改動,此時再利用順序埠連線進行模組例化,顯然是不方便的。所以平時,建議採用命名埠方式對模組進行例化。
埠連線規則
輸入埠
模組例化時,從模組外部來講, input 埠可以連線 wire 或 reg 型變數。這與模組宣告是不同的,從模組內部來講,input 埠必須是 wire 型變數。
輸出埠
模組例化時,從模組外部來講,output 埠必須連線 wire 型變數。這與模組宣告是不同的,從模組內部來講,output 埠可以是 wire 或 reg 型變數。
輸入輸出埠
模組例化時,從模組外部來講,inout 埠必須連線 wire 型變數。這與模組宣告是相同的。
懸空埠
模組例化時,如果某些訊號不需要與外部訊號進行連線互動,我們可以將其懸空,即埠例化處保留空白即可,上述例子中有提及。
//下述程式碼編譯會報Warning
full_adder4 u_adder4(
.a (a),
.b (b),
.c (),
.so (so),
.co (co));
//如果模組full_adder4有input埠c,則下述程式碼編譯是會報Error
一般來說,建議 input 埠不要做懸空處理,無其他外部連線時賦值其常量,例如:
.c (1"b0),
位寬匹配
當例化埠與連續訊號位寬不匹配時,埠會透過無符號數的右對齊或截斷方式進行匹配。
假如在模組 full_adder4 中,埠 a 和埠 b 的位寬都為 4bit,則下面程式碼的例化結果會導致:u_adder4.a = {2"bzz, a[1:0]}, u_adder4.b = b[3:0] 。
.a (a[1:0]), //input a[3:0]
.b (b[5:0]), //input b[3:0]
埠連續訊號型別
連線埠的訊號型別可以是,1)識別符號,2)位選擇,3)部分選擇,4)上述型別的合併,5)用於輸入埠的表示式。
當然,訊號名字可以與埠名字一樣,但他們的意義是不一樣的,分別代表的是 2 個模組內的訊號。
用 generate 進行模組例化
當例化多個相同的模組時,一個一個的手動例化會比較繁瑣。用 generate 語句進行多個模組的重複例化,可大大簡化程式的編寫過程。
重複例化 4 個 1bit 全加器組成一個 4bit 全加器的程式碼如下:
module full_adder4(
input [3:0] a , //adder1
input [3:0] b , //adder2
input c , //input carry bit
output [3:0] so , //adding result
output co //output carry bit
);
wire [3:0] co_temp ;
//第一個例化模組一般格式有所差異,需要單獨例化
.Ci (c==1"b1 ? 1"b1 : 1"b0),
.So (so[0]),
genvar i ;
generate
for(i=1; i<=3; i=i+1) begin: adder_gen
full_adder1 u_adder(
.Ai (a[i]),
.Bi (b[i]),
.Ci (co_temp[i-1]), //上一個全加器的溢位是下一個的進位
.So (so[i]),
.Co (co_temp[i]));
end
endgenerate
assign co = co_temp[3] ;
endmodule
testbench 如下:
`timescale 1ns/1ns
module test ;
reg [3:0] a ;
reg [3:0] b ;
//reg c ;
wire [3:0] so ;
wire co ;
//簡單驅動
initial begin
a = 4"d5 ;
b = 4"d2 ;
#10 ;
a = 4"d10 ;
b = 4"d8 ;
.c (1"b0), //埠可以連線常量
forever begin
#100;
if ($time >= 1000) $finish ;
endmodule // test
模擬結果如下,可知 4bit 全加器工作正常:
層次訪問
每一個例化模組的名字,每個模組的訊號變數等,都使用一個特定的識別符號進行定義。在整個層次設計中,每個識別符號都具有唯一的位置與名字。
Verilog 中,透過使用一連串的 . 符號對各個模組的識別符號進行層次分隔連線,就可以在任何地方透過指定完整的層次名對整個設計中的識別符號進行訪問。
層次訪問多見於模擬中。
例如,有以下層次設計,則葉單元、子模組和頂層模組間的訊號就可以相互訪問。
//u_n1模組中訪問u_n3模組訊號:
a = top.u_m2.u_n3.c ;
//u_n1模組中訪問top模組訊號
if (top.p == "b0) a = 1"b1 ;
//top模組中訪問u_n4模組訊號
assign p = top.u_m2.u_n4.d ;
前面章節的模擬中,或多或少的也進行過相關的層次訪問。例如《過程連續賦值》一節中,在頂層模擬激勵 test 模組中使用瞭如下語句:
wait (test.u_counter.cnt_temp == 4"d4) ;
關鍵字:例化,generate,全加器,層次訪問
在一個模組中引用另一個模組,對其埠進行相關連線,叫做模組例化。模組例化建立了描述的層次。訊號埠可以透過位置或名稱關聯,埠連線也必須遵循一些規則。
命名埠連線
這種方法將需要例化的模組埠與外部訊號按照其名字進行連線,埠順序隨意,可以與引用 module 的宣告埠順序不一致,只要保證埠名字與外部訊號匹配即可。
下面是例化一次 1bit 全加器的例子:
例項
full_adder1 u_adder0(
.Ai (a[0]),
.Bi (b[0]),
.Ci (c==1"b1 ? 1"b0 : 1"b1),
.So (so_bit0),
.Co (co_temp[0]));
例項
//output 埠 Co 懸空
full_adder1 u_adder0(
.Ai (a[0]),
.Bi (b[0]),
.Ci (c==1"b1 ? 1"b0 : 1"b1),
.So (so_bit0),
.Co ());
full_adder1 u_adder0(
.Ai (a[0]),
.Bi (b[0]),
.Ci (c==1"b1 ? 1"b0 : 1"b1),
.So (so_bit0));
順序埠連線
這種方法將需要例化的模組埠按照模組宣告時埠的順序與外部訊號進行匹配連線,位置要嚴格保持一致。例如例化一次 1bit 全加器的程式碼可以改為:
full_adder1 u_adder1(
a[1], b[1], co_temp[0], so_bit1, co_temp[1]);
雖然程式碼從書寫上可能會佔用相對較少的空間,但程式碼可讀性降低,也不易於除錯。有時候在大型的設計中可能會有很多個埠,埠訊號的順序時不時的可能也會有所改動,此時再利用順序埠連線進行模組例化,顯然是不方便的。所以平時,建議採用命名埠方式對模組進行例化。
埠連線規則
輸入埠
模組例化時,從模組外部來講, input 埠可以連線 wire 或 reg 型變數。這與模組宣告是不同的,從模組內部來講,input 埠必須是 wire 型變數。
輸出埠
模組例化時,從模組外部來講,output 埠必須連線 wire 型變數。這與模組宣告是不同的,從模組內部來講,output 埠可以是 wire 或 reg 型變數。
輸入輸出埠
模組例化時,從模組外部來講,inout 埠必須連線 wire 型變數。這與模組宣告是相同的。
懸空埠
模組例化時,如果某些訊號不需要與外部訊號進行連線互動,我們可以將其懸空,即埠例化處保留空白即可,上述例子中有提及。
例項
//下述程式碼編譯會報Warning
full_adder4 u_adder4(
.a (a),
.b (b),
.c (),
.so (so),
.co (co));
例項
//如果模組full_adder4有input埠c,則下述程式碼編譯是會報Error
full_adder4 u_adder4(
.a (a),
.b (b),
.so (so),
.co (co));
一般來說,建議 input 埠不要做懸空處理,無其他外部連線時賦值其常量,例如:
例項
full_adder4 u_adder4(
.a (a),
.b (b),
.c (1"b0),
.so (so),
.co (co));
位寬匹配
當例化埠與連續訊號位寬不匹配時,埠會透過無符號數的右對齊或截斷方式進行匹配。
假如在模組 full_adder4 中,埠 a 和埠 b 的位寬都為 4bit,則下面程式碼的例化結果會導致:u_adder4.a = {2"bzz, a[1:0]}, u_adder4.b = b[3:0] 。
例項
full_adder4 u_adder4(
.a (a[1:0]), //input a[3:0]
.b (b[5:0]), //input b[3:0]
.c (1"b0),
.so (so),
.co (co));
埠連續訊號型別
連線埠的訊號型別可以是,1)識別符號,2)位選擇,3)部分選擇,4)上述型別的合併,5)用於輸入埠的表示式。
當然,訊號名字可以與埠名字一樣,但他們的意義是不一樣的,分別代表的是 2 個模組內的訊號。
用 generate 進行模組例化
當例化多個相同的模組時,一個一個的手動例化會比較繁瑣。用 generate 語句進行多個模組的重複例化,可大大簡化程式的編寫過程。
重複例化 4 個 1bit 全加器組成一個 4bit 全加器的程式碼如下:
例項
module full_adder4(
input [3:0] a , //adder1
input [3:0] b , //adder2
input c , //input carry bit
output [3:0] so , //adding result
output co //output carry bit
);
wire [3:0] co_temp ;
//第一個例化模組一般格式有所差異,需要單獨例化
full_adder1 u_adder0(
.Ai (a[0]),
.Bi (b[0]),
.Ci (c==1"b1 ? 1"b1 : 1"b0),
.So (so[0]),
.Co (co_temp[0]));
genvar i ;
generate
for(i=1; i<=3; i=i+1) begin: adder_gen
full_adder1 u_adder(
.Ai (a[i]),
.Bi (b[i]),
.Ci (co_temp[i-1]), //上一個全加器的溢位是下一個的進位
.So (so[i]),
.Co (co_temp[i]));
end
endgenerate
assign co = co_temp[3] ;
endmodule
testbench 如下:
例項
`timescale 1ns/1ns
module test ;
reg [3:0] a ;
reg [3:0] b ;
//reg c ;
wire [3:0] so ;
wire co ;
//簡單驅動
initial begin
a = 4"d5 ;
b = 4"d2 ;
#10 ;
a = 4"d10 ;
b = 4"d8 ;
end
full_adder4 u_adder4(
.a (a),
.b (b),
.c (1"b0), //埠可以連線常量
.so (so),
.co (co));
initial begin
forever begin
#100;
if ($time >= 1000) $finish ;
end
end
endmodule // test
模擬結果如下,可知 4bit 全加器工作正常:
層次訪問
每一個例化模組的名字,每個模組的訊號變數等,都使用一個特定的識別符號進行定義。在整個層次設計中,每個識別符號都具有唯一的位置與名字。
Verilog 中,透過使用一連串的 . 符號對各個模組的識別符號進行層次分隔連線,就可以在任何地方透過指定完整的層次名對整個設計中的識別符號進行訪問。
層次訪問多見於模擬中。
例如,有以下層次設計,則葉單元、子模組和頂層模組間的訊號就可以相互訪問。
例項
//u_n1模組中訪問u_n3模組訊號:
a = top.u_m2.u_n3.c ;
//u_n1模組中訪問top模組訊號
if (top.p == "b0) a = 1"b1 ;
//top模組中訪問u_n4模組訊號
assign p = top.u_m2.u_n4.d ;
前面章節的模擬中,或多或少的也進行過相關的層次訪問。例如《過程連續賦值》一節中,在頂層模擬激勵 test 模組中使用瞭如下語句:
wait (test.u_counter.cnt_temp == 4"d4) ;