關鍵詞:模塊,端口,雙向端口,PAD
結構建模方式有 3 類描述語句: Gate(門級)例化語句,UDP (用戶定義原語)例化語句和 module (模塊) 例化語句。本次主要講述使用最多的模塊級例化語句。
模塊
模塊是 Verilog 中基本單元的定義形式,是與外界交互的接口。
模塊格式定義如下:
module module_name #(parameter_list) (port_list) ; Declarations_and_Statements ; endmodule
模塊定義必須以關鍵字 module 開始,以關鍵字 endmodule 結束。
模塊名,端口信號,端口聲明和可選的參數聲明等,出現在設計使用的 Verilog 語句(圖中 Declarations_and_Statements)之前。
模塊內部有可選的 5 部分組成,分別是變量聲明,數據流語句,行為級語句,低層模塊例化及任務和函數,如下圖表示。這 5 部分出現順序、出現位置都是任意的。但是,各種變量都應在使用之前聲明。變量具體聲明的位置不要求,但必須保證在使用之前的位置。
前麵大多數仿真代碼都會用到 module 聲明,大家可以自行參考,這裏不再做具體舉例。下麵介紹端口時,再做詳細的仿真。
端口
端口是模塊與外界交互的接口。對於外部環境來說,模塊內部是不可見的,對模塊的調用隻能通過端口連接進行。
端口列表
模塊的定義中包含一個可選的端口列表,一般將不帶類型、不帶位寬的信號變量羅列在模塊聲明裏。下麵是一個 PAD 模型的端口列表:
module pad( DIN, OEN, PULL, DOUT, PAD);
一個模塊如果和外部環境沒有交互,則可以不用聲明端口列表。例如之前我們仿真時 test.sv 文件中的 test 模塊都沒有聲明具體端口。
module test ; //直接分號結束 ...... //數據流或行為級描述 endmodule
端口聲明
(1) 端口信號在端口列表中羅列出來以後,就可以在模塊實體中進行聲明了。
根據端口的方向,端口類型有 3 種: 輸入(input),輸出(output)和雙向端口(inout)。
input、inout 類型不能聲明為 reg 數據類型,因為 reg 類型是用於保存數值的,而輸入端口隻能反映與其相連的外部信號的變化,不能保存這些信號的值。
output 可以聲明為 wire 或 reg 數據類型。
上述例子中 pad 模塊的端口聲明,在 module 實體中就可以表示如下:
實例
input DIN, OEN ;
input [1:0] PULL ; //(00,01-dispull, 11-pullup, 10-pulldown)
inout PAD ; //pad value
output DOUT ; //pad load when pad configured as input
//端口數據類型聲明
wire DIN, OEN ;
wire [1:0] PULL ;
wire PAD ;
reg DOUT ;
(2) 在 Verilog 中,端口隱式的聲明為 wire 型變量,即當端口具有 wire 屬性時,不用再次聲明端口類型為 wire 型。但是,當端口有 reg 屬性時,則 reg 聲明不可省略。
上述例子中的端口聲明,則可以簡化為:
實例
input DIN, OEN ;
input [1:0] PULL ;
inout PAD ;
output DOUT ;
reg DOUT ;
(3) 當然,信號 DOUT 的聲明完全可以合並成一句:
output reg DOUT ;
(4) 還有一種更簡潔且常用的方法來聲明端口,即在 module 聲明時就陳列出端口及其類型。reg 型端口要麼在 module 聲明時聲明,要麼在 module 實體中聲明,例如以下 2 種寫法是等效的。
實例
input DIN, OEN ,
input [1:0] PULL ,
inout PAD ,
output reg DOUT
);
module pad(
input DIN, OEN ,
input [1:0] PULL ,
inout PAD ,
output DOUT
);
reg DOUT ;
inout 端口仿真
對包含有 inout 端口類型的 pad 模型進行仿真。pad 模型完整代碼如下:
實例
//DIN, pad driver when pad configured as output
//OEN, pad direction(1-input, o-output)
input DIN, OEN ,
//pull function (00,01-dispull, 10-pullup, 11-pulldown)
input [1:0] PULL ,
inout PAD ,
//pad load when pad configured as input
output reg DOUT
);
//input:(not effect pad external input logic), output: DIN->PAD
assign PAD = OEN? 'bz : DIN ;
//input:(PAD->DOUT)
always @(*) begin
if (OEN == 1) begin //input
DOUT = PAD ;
end
else begin
DOUT = 'bz ;
end
end
//use tristate gate in Verilog to realize pull up/down function
bufif1 puller(PAD, PULL[0], PULL[1]);
endmodule
testbench代碼如下:
實例
module test ;
reg DIN, OEN ;
reg [1:0] PULL ;
wire PAD ;
wire DOUT ;
reg PAD_REG ;
assign PAD = OEN ? PAD_REG : 1'bz ; //
initial begin
PAD_REG = 1'bz ; //pad with no dirve at first
OEN = 1'b1 ; //input simulation
#0 ; PULL = 2'b10 ; //pull down
#20 ; PULL = 2'b11 ; //pull up
#20 ; PULL = 2'b00 ; //dispull
#20 ; PAD_REG = 1'b0 ;
#20 ; PAD_REG = 1'b1 ;
#30 ; OEN = 1'b0 ; //output simulation
DIN = 1'bz ;
#15 ; DIN = 1'b0 ;
#15 ; DIN = 1'b1 ;
end
pad u_pad(
.DIN (DIN) ,
.OEN (OEN) ,
.PULL (PULL) ,
.PAD (PAD) ,
.DOUT (DOUT)
);
initial begin
forever begin
#100;
if ($time >= 1000) $finish ;
end
end
endmodule // test
仿真結果如下:
仿真結果分析如下:
當 PAD 方向為 input 且沒有驅動時,pull 功能能通過 PAD 的值而體現。
前 60ns 內,PAD 的驅動端 PAD_REG 為 z, 可認為沒有驅動,所以開始時 PULL=2, 下拉,PAD值為 0; 20ns 時,PULL=3,上拉,PAD 值為 1;
40ns 時,PULL=0,沒有 pull 功能,PAD 值輸入為 z。
60ns~100ns 後,PAD 的驅動端 PAD_REG 開始正常驅動。此時相當於 PAD 直接與 PAD_REG 相連,所以 PAD 值與其驅動值保持一致。
以上分析,PAD 方向都是 input,所有輸出端 DOUT 與 PAD 值保持一致。
當 PAD 方向為 output 時,即 120ns 時 OEN= 0,PAD 值與輸入端 DIN 值保持一致。