• 【设计经验】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之禅

  • 相关阅读:
    Js $.merge() 函数(合并两个数组内容到第一个数组)
    11.联结表---SQL
    函数作用域
    递归特性
    计算递归函数理解
    递归、问路函数
    全局变量用大写,局部变量用小写
    全局变量与局部变量
    函数形参和实参
    函数和过程
  • 原文地址:https://www.cnblogs.com/liujinggang/p/9780767.html
Copyright © 2020-2023  润新知