在查閱了各種書和帖子之后,總結了以下inout端口的使用注意事項。
(以下資料來源:
《Xilinx FPGA開發實用教程 第二版》
https://www.cnblogs.com/sea-wind/p/4924567.html 《FPGA中的INOUT接口和高阻態》
https://blog.csdn.net/kebu12345678/article/details/80587614 《FPGA中inout端口使用方法總結 (Verilog)》
https://blog.csdn.net/u013608424/article/details/72865722 《FPGA學習之inout雙向口》
)
首先是一些要先理解的基本概念:
0、什么是雙向端口inout端口
顧名思義,雙向端口既可以作為輸入端口接收數據,也可以作為輸出端口發出數據,它對數據的操作是雙向的。雙向端口在綜合時是以三態門的形式存在的,其典型結構如圖所示。

1、三態門
在Xilinx的《XST User Guide》中給出了三態門的verilog描述

1 // Tristate Description Using Concurrent Assignment 2 3 // Combinatorial Always Block Can be Used too. 4 5 module v_three_st_2 (T, I, O); 6 7 input T, I; 8 9 output O; 10 11 assign O = (~T) ? I: 1’bZ; 12 13 endmodule
上述描述表明,當控制信號T=1時,管子被置為高阻態,輸出O為高阻態;當控制信號T=0時,管子開通,輸出O=輸入I。(跟控制信號T是高有效或低有效有關)
2、高阻和懸空
三態門中有一個狀態是高阻。高阻,即可以認為是沒有輸出,作為輸出端口而言,對下級電路沒有任何影響。懸空是針對輸入端口來說的,也就是說沒有接輸入。這也就意味着,實際上高阻和懸空是一個狀態,在HDL語言里都表示為Z。
也就是說,一個輸出端口在高阻態的時候,其狀態是由於其相連的其他電路決定的,可以將其看作是輸入。
雙向端口用作輸出時,就和平常一樣,但雙向端口作輸入引腳時需要將此引腳置為高阻態,這樣其電平就可以由外部輸入信號決定了(這是高阻態的特性)。
在上述基本概念的基礎上,討論三個方面的問題:
一、雙向端口的實現原理

通過上面的基本概念應該已經清楚雙向端口的實現原理了,只要搞清楚上面管子的開通狀態與整個雙向端口的對外特性之間的關系就行了。
當上面的管子開通時,此時數據可以從上面的管子中通過,此時雙向端口為輸出端口,Device IO的賦值 from FPGA。
當上面的管子被置為高阻態時,數據只能從下面的管子通過,此時雙向端口為輸入端口,Device IO的賦值 to FPGA。
而控制信號T與管子開關狀態之間的關系下面結合代碼來講。
二、雙向端口的Verilog實現
在Verilog中實現雙向端口,首先要明確inout端口的變量類型。inout端口只能被定義為net型變量,只能采用assign賦值語句,不能在always塊內使用,詳細解釋可以看我的另一篇博客《【Verilog HDL】Verilog的端口類型以及端口連接規則 》。要注意這一點與VHDL中雙向端口是使用方法不同。
接下來的代碼展示了在輸入情況下和輸出情況下的賦值語句。
1 module inout_def(clk,data_inout) 2 input clk; 3 inout data_inout; 4 reg data_out; 5 reg data_out_control; 6 //define data_out 7 8 //define data_out_control 9 10 //assign data_inout 11 assign data_inout=data_out_control?data_out:1'bz; 12 13 //assign data_in 14 wire data_in; 15 assign data_in=(!data_out_control)&data_inout; 16 17 endmodule
控制信號data_out_control決定了雙向端口data_inout的特性。當data_out_control=1時,data_inout作輸出,此時將data_out的值賦給data_inout;當data_out_control=0時,data_inout作輸入,將data_inout賦給data_in。
不同需求的雙向端口,它的assign賦值語句的寫法也是不同的:
當雙向端口作輸出時,assign data_inout=data_out_control?data_out:1'bz;
當雙向端口作輸入時,要將三態門置為高阻態,也就是要有data_inout = 1'bz,此時控制信號等於0,所以有 assign data_in=(!data_out_control)&data_inout;
三、雙向端口的仿真
編寫測試模塊時,對於inout類型的端口,需要定義成wire型變量,而其他輸入端口都定義成reg型,這兩者是有區別的。
當上面的例子中的data_inout用作輸入時,需要賦值給data_inout,其余情況可以斷開。此時可以用assign語句實現:
assign data_inout = link ? data_in_t : 1'bz;
其中的link,data_in_t是reg型變量,在tb文件中賦值。
另外,可以設置一個輸出端口觀察data_inout用作輸出的情況:
wire data_out;
assign data_out_t = (!link) ? data_inout : 1'bz;
需要注意的是:當給data_inout賦值的時候(它作輸入端口時),只能在原INOUT數據為高阻態時才可以賦值,所以link信號即該INOUT數據為高阻態時的控制信號,也就是說link = !data_out_control;當不需要測試文件給data_inout數據賦值的時候,測試文件的data_inout接口因為高阻態,從而不影響源文件data_inout接口的其它操作。
