在FPGA的設計過程中,有時候會遇到雙向信號(既能作為輸出,也能作為輸入的信號叫雙向信號)。比如,IIC總線中的SDA信號就是一個雙向信號,QSPI Flash的四線操作的時候四根信號線均為雙向信號。在Verilog中用關鍵字inout定義雙向信號,這里總結一下雙向信號的處理方法。
實際上,雙向信號的本質是由一個三態門組成的,三態門可以輸出高電平,低電平和高阻態三種狀態,在FPGA中,一個三態門的結構如下圖所示:
描述這個邏輯的Verilog代碼如下:
module inout_top ( input I_data_in , inout IO_data , output O_data_out , input Control ); assign IO_data = Control ? I_data_in : 1'bz ; assign O_data_out = IO_data ; endmodule
當Control為1時,IO_data為輸出,輸出I_data_in的值
當Control為0時,IO_data為輸入,把輸入的信號賦值給O_data_out
這段代碼在Vivado2015.4.2編譯環境下的RTL圖如下圖所示
在ISE14.7的編譯環境下的RTL圖如下圖所示
可以發現在Vivado2015.4.2環境的Control信號的IBUF后面居然還綜合出了一個LUT,在ISE14.7環境下Control信號后面綜合出了一個反向器,出現這個LUT和反向器的原因是Control為1才把IO_data設置成輸出,而在Xilinx中一個IOBUF資源默認T端為0時IO端才為輸出,T端為1時,IO端為輸入,所以把
assign IO_data = Control ? I_data_in : 1'bz ;
改為
assign IO_data = (Control == 1’b0) ? I_data_in : 1'bz ;
在Vivado2015.4.2環境下綜合出的RTL圖為下圖
在ISE14.7的環境下綜合出的RTL圖如下圖所示
顯然,Vivado環境中LUT和ISE環境中的反相器不見了,節省了1個Cell資源。
以上是處理inout的第一種方法,第二種處理inout信號的方法是調用Xilinx的IOBUF原語,IOBUF的原語可以在Vivado2015.4.2的Language Templates中找到
調用這個原語的Verilog代碼如下:
module inout_top ( input I_data_in, inout IO_data , output O_data_out , input Control ); IOBUF #( .DRIVE(12), // Specify the output drive strength .IBUF_LOW_PWR("TRUE"), // Low Power - "TRUE", High Performance = "FALSE" .IOSTANDARD("DEFAULT"), // Specify the I/O standard .SLEW("SLOW") // Specify the output slew rate ) IOBUF_inst ( .O(O_data_out), // Buffer output .IO(IO_data), // Buffer inout port (connect directly to top-level port) .I(I_data_in), // Buffer input .T(Control) // 3-state enable input, high=input, low=output ); endmodule
在Vivado2015.4.2環境下綜合出的RTL圖如下圖所示
在ISE14.7環境下綜合出的RTL圖如下圖所示
顯然和 assign IO_data = (Control == 1’b0) ? I_data_in : 1'bz ;這種情況下綜合出的RTL完全一樣。
總結,利用Verilog處理雙向信號有兩種方式:
1、寫代碼
assign IO_data = (Control == 1’b0)? I_data_in : 1'bz ;
assign O_data_out = IO_data ;
2、例化IOBUF原語
IOBUF #(
.DRIVE(12), // Specify the output drive strength
.IBUF_LOW_PWR("TRUE"), // Low Power - "TRUE", High Performance = "FALSE"
.IOSTANDARD("DEFAULT"), // Specify the I/O standard
.SLEW("SLOW") // Specify the output slew rate
) IOBUF_inst (
.O(O_data_out), // Buffer output
.IO(IO_data), // Buffer inout port (connect directly to top-level port)
.I(I_data_in), // Buffer input
.T(Control) // 3-state enable input, high=input, low=output
);
題外話:
最近調一套代碼,代碼是前輩寫的,之前都是用ISE開發,那套代碼用ISE編譯出的bit文件可以正常運行,但是最新的項目由於要添加更多的功能,所以選用了K7系列的FPGA,在Vivado下開發,結果發現原來正常運行的代碼在Vivado下就不能運行了,通過反復檢查與定位,發現原來的那套代碼對inout信號的處理十分不規范,而且沒有加Control這個控制信號來控制inout的方向,直接想當然的作為輸入或者輸出來使用。最后我們把inout信號全部采用上面兩種規范的處理方法處理以后,代碼正常運行。所以平時在設計的過程中一定要多注意細節,力求規范。
歡迎關注我的公眾號:FPGA之禪