【設計經驗】1、Verilog中如何規范的處理inout信號


  在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之禪


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM