不枉初心,砥砺前行

皮皮祥的博客

欢迎留言,评论

导航

三态(tri-state)门、双向(bi-directional)端口的建模、仿真和综合

目录

1. 概要

2. 三态门 

2.1 概念

2.2 三态门建模

3. 双向端口

3.1 HDL语言描述

3.2 直接调用元件库中的模块

3. 仿真

4. 综合


1. 概要

        双向端口顾名思义是一种既可以作为输入端口接收数据,也可以作为输出端口发出数据,它对数据的操作是双向的。比如某个设计需要一个 16 位的数据输入口和一个16 位的数据输出口,并且数据输入和输出不会同时发生。 如果数据输入口和输出口分别设计则需要32根数据线,而用双向端口来设计,则只需要16根数据线,这样就节省了16根数据线引脚。在很多情况下,芯片端口是宝贵的设计资源,而且芯片间的连线少对于板级设计也非常有利。因此,双向端口常用于芯片间需要进行半双工双向通信的场合,可以节省一半芯片端口以及减少板上芯片间连接的走线。

        常见的一些例子有:

        . I2C总线中的SDA信号线

        . AXI总线中的数据线

        . JESD207接口中的数据线DIQ、等等

        在电路层面,双向端口是通过三态缓冲器(也称三态门)控制实现的。在数字电路中,逻辑输出有两个正常态:低电平状态(逻辑0)和高电平状态(逻辑1),此外,电路还有不属于0和1的高阻态(逻辑Z)。所谓高阻,即输出端处于浮空状态,只有很小的漏电流流动,其电平随外部电平的高低而定,门电平放弃对输出电路的控制,或者可以理解为输出和电路是断开的。

2. 三态门 

2.1 概念

        在数字电路中,逻辑输出有两个正常态:低电平状态(对应逻辑0)和高电平状态(对应逻辑1);此外,电路还有不属于0和1状态的高阻态(对应逻辑Z  )。所谓高阻,即输出端属于浮空状态,只有很小的漏电流流动,其电平随外部电平高低而定,门电平放弃对输出电路的控制。或者可以理解为输出与电路是断开的。最基本的三态缓冲器的逻辑符号如下图:

        当OE为高电平时,Dataout与Datain相连,数据流向是从Datain向Dataout;而OE为低时,Dataout为高阻态,相当于与Datain之间的连线断开,此时可以从外部向Dataout驱动信号,实现相反方向的数据流向。

2.2 三态门建模

        三态门的RTL描述方式有以下两种等价的方式。

  1.  
    // Tristate Description Using Combinatorial Always Block
  2.  
    // File: tristates_1.v
  3.  
    //
  4.  
     
  5.  
    module tristates_1 (OE, I, O);
  6.  
     
  7.  
    input OE, I;
  8.  
    output O;
  9.  
    reg O;
  10.  
     
  11.  
    always @(OE or I)
  12.  
    begin
  13.  
    if (OE)
  14.  
    O = I;
  15.  
    else
  16.  
    O = 1'bZ;
  17.  
    end
  18.  
     
  19.  
    endmodule
  1.  
    // Tristate Description Using Concurrent Assignment
  2.  
    // File: tristates_2.v
  3.  
    //
  4.  
     
  5.  
    module tristates_2 (OE, I, O);
  6.  
     
  7.  
    input T, I;
  8.  
    output O;
  9.  
     
  10.  
    assign O = (OE) ? I: 1'bZ;
  11.  
     
  12.  
    endmodule

3. 双向端口

        通常两种双向端口建模的方法。

        第一种是直接用HDL语言进行行为级描述,基于以上三态门的RTL描述,稍作修改即可。另一种则是直接调用元件库(cell library)中的模块,比如说Xilinx FPGA中的IOBUF等。后者通常只用于在纯粹的FPGA开发(即FPGA实现就是最终实现)中,在芯片开发中,应该采用第一种,如果采用第二种描述的话,将会导致FPGA综合代码与芯片实现代码不一致,并导致FPGA原型验证的有效性受损,这是应该尽量避免的。

3.1 HDL语言描述

        以下为双向端口的两个行为级描述的module例。其中第一个有时钟控制,以同步于时钟沿的方式工作,第二个是存粹的组合逻辑描述方式。前者从综合时序的角度来说会更好一些。

  1.  
    module BIDIR_CLKED
  2.  
    #(
  3.  
    parameter P_WIDTH = 6'd1 //
  4.  
    )
  5.  
    (
  6.  
    input CLK ,
  7.  
    input OE , // 1: Output port; 0: Input port
  8.  
    input [P_WIDTH-1:0] DIN ,
  9.  
    output [P_WIDTH-1:0] DOUT ,
  10.  
    inout [P_WIDTH-1:0] BIDIR
  11.  
    );
  12.  
     
  13.  
    reg [P_WIDTH-1:0] din_reg;
  14.  
    reg [P_WIDTH-1:0] dout_reg;
  15.  
     
  16.  
    assign BIDIR = OE ? din_reg : {P_WIDTH{1'bZ}};
  17.  
    assign DOUT = dout_reg;
  18.  
     
  19.  
    // Pipelining
  20.  
    always @ (posedge CLK)
  21.  
    begin
  22.  
    din_reg <= DIN;
  23.  
    dout_reg <= BIDIR;
  24.  
    end
  25.  
     
  26.  
    endmodule
  1.  
    module BIDIR
  2.  
    #(
  3.  
    parameter P_WIDTH = 6'd1 //
  4.  
    )
  5.  
    (
  6.  
    input CLK ,
  7.  
    input OE , // 1: Output port; 0: Input port
  8.  
    input [P_WIDTH-1:0] DIN ,
  9.  
    output [P_WIDTH-1:0] DOUT ,
  10.  
    inout [P_WIDTH-1:0] BIDIREC
  11.  
    );
  12.  
     
  13.  
    assign BIDIREC = OE ? DIN : {P_WIDTH{1'bZ}}; // DIN --> BIDIREC
  14.  
    assign DOUT = {P_WIDTH{~OE}} & BIDIREC; // BIDIREC --> DOUT
  15.  
     
  16.  
    endmodule

3.2 直接调用元件库中的模块

        不管是FPGA还是ASIC其标准单元库中通常都会包含双向端口单元。以Xilinx为例,它提供了IOBUF单元(另外,还有IOBUF_DIFF_OUT、IOBUFDS等),IOBUF的符号、真值表如下所示(参见UG768):

         以下是两个直接实例化IOBUF的代码例。第一个是1比特的双向端口的IOBUF实例化;第二个是一个多比特的双向总线模块,在该模块中实例化了多个IOBUF。

3. 仿真

        以下案例取自于一个实际的JESD207接口设计,JESD207接口中DIQ信号线是双向信号线。上半部分代码是DUT中实例化BIDIR_CLKED实现双向端口JESD207.DIQ;下半部分为testbench中的处理。

  1.  
    // ***************************************************************************
  2.  
    //BIDIR instantiation in DUT
  3.  
    wire [11:0] diq_tx;
  4.  
    wire [11:0] diq_rx;
  5.  
    assign diq_rx = ...;
  6.  
    BIDIR_CLKED #(12) u_BIDIR_CLKED
  7.  
    (
  8.  
    .CLK (CLK ),
  9.  
    .OE (DIQ_OE ), // 0: RX; 1: TX
  10.  
    .DIN (diq_tx ),
  11.  
    .DOUT (diq_rx ),
  12.  
    .BIDIREC(DIQ )
  13.  
    );
  14.  
     
  15.  
    // ***************************************************************************
  16.  
    //Signal assignment in testbench.
  17.  
    logic diq_oe; // Connect to DUT.DIQ_OE port
  18.  
    wire [11:0] tx_diq;
  19.  
    wire [11:0] rx_diq;
  20.  
    wire [11:0] diq; // Connect to DUT.DIQ port
  21.  
    assign diq = diq_oe ? {12{1'bZ}}: rx_diq;
  22.  
    assign tx_diq = diq;
  23.  
    // ***************************************************************************

        需要注意的是,在testbench中,对应于DIQ的信号需要定义成wire类型。此外,对于双向端口/信号的描述,在DUT和testbench中是互补的。如以上代码例所示,由当DUT.DIQ在DIQ_OE的控制下作为输出端口使用,testbench中则应该是要作为输入信号处理,即接收DUT输出的信号;反之,当DUT.DIQ在DIQ_OE的控制下作为输入端口使用,testbench中则应该是要作为输出信号处理,即对DIQ信号进行驱动赋值。

4. 综合

        如上所述,作为芯片设计的FPGA原型验证时,应该使用行为级的方式描述双向端口。但是如何确认描述是否正确呢?一般来说仿真当然可以在很大程度确认这一点,但是更为直接方式是针对综合生成电路进行直接确认,确认综合工具是否正确地将行为级描述正确地推断(infer)为IOBUF。

     以上所述的JESD207接口的Vivado综合为例,在综合结束后,从Vivado界面点击SynthesisàOpen Synthesized DesignàSchematic打开综合生成的电路图,可以找到如下图所示的对应JESD_DIQ接口电路图。从图中可以明确地看出JESD207接口的DIQ端口被正确地推断为IOBUF。

        不管用BIDIR还是用BIDIR_CLKED都可以综合得出以上结果。        

        芯片综合工具通常也提供查看综合后电路的功能,可以以相同的方式进行直接确认。

参考文献

[1] Tristates • Vivado Design Suite User Guide: Synthesis (UG901) 

posted on 2022-12-20 22:02  皮皮祥  阅读(500)  评论(0编辑  收藏  举报