[转帖]INOUT双向端口仿真 三态门构成 三态门原理 三态门仿真

来源:http://blog.sina.com.cn/s/blog_66eaee8f0100hrjl.html

http://www.cnblogs.com/oomusou/archive/2011/02/21/inout_port.html

INOUT双向端口仿真 三态门构成 三态门原理 三态门仿真

(2010-04-10 00:17:54)

转载

 

分类: FPGA

HDL语言的INOUT双向端口仿真暨三态门仿真

------VHDL和VerilogHDL

韦志恒 weizhiheng99@yahoo.com.cn

概述

    三态门是FPGA编程开发中经常遇到的一个问题。一个典型的应用就是TI的DSP的EMIF总线。针对HDL语言的三态门应用示例和仿真示例在网上很多,但是往往只讲述一种语言的,没有给予两种语言下三态门的一个综合评述,如讲述二者使用、仿真时的区别等。特别是VerilogHDL语言下的三态门仿真,很多讲述都是语焉不详,包括使用Force语句等,这些使用人手工干预的仿真方法明显违背了EDA自动化的宗旨,是使用者对其仿真方法不明确的情况下的一种权益之计。

本文将使用一个DSP EMIF接口逻辑的例子,详细讲述:

(0)什么叫做Z态?三态的晶体管级实现是怎样的?

(1)VHDL语言下同步、异步三态门的实现和仿真;

(2)VerilogHDL语言下同步、异步三态门的实现和仿真;

(3)综述两种语言下仿真的要点。

一 双向管脚INOUT与三态门介绍

三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t">
 

图1 一个典型的FPGA的管脚

由图1可以看出,一个FPGA的管脚由一个输入缓冲器和一个三态输出缓冲器构成。

三态输出缓冲器,即三态门,是指逻辑门的输出除有高、低电平两种状态外,还有第三种状态——高阻状态的门电路。高阻态相当于隔断状态(电阻很大,相当于开路)。三态门都有一个EN控制使能端,来控制门电路的通断。可以具备这三种状态的器件就叫做三态。

准确来讲,三态的高阻态(Z态)指的就是门的输出脚的两个驱动TTL或MOS管都处于截止状态时的输出状态。参考图2、图3和图4有更详细的理解。

 三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t">

图2  TTL逻辑三态门的构成图

三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t"> 端接低电平时,反相器输出一个高电平给T1 ,使整个电路处于工作状态,这样,电路将按与非关系把A, B接受到的信号传送到输出端, 使Y或为高电平,或为低电平。当三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t"> 端接高电平时,反相器输出低电平给T1,使 T1、T5截止。另一方面,通过D把T4的基极电位钳在1v左右,使T4截止。由于T4、T5均截止,从输出端Y看进去,电路处于高阻状态。

 三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t">

图3 CMOS三态门实现A

对于CMOS的三态门,可以分析:当三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t"> 为0时,T1’和T2’都处于导通状态,因此T1和T2能够在A为1或0时分别导通,因此Y输出A的状态;反之,当三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t"> 为1时,T1’和T2’都处于截止状态,T1和T2自然也处于截止状态,因此Y就处于高阻状态。

三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t"> 

图4 CMOS三态门实现B—利用传输门实现的三态门

 三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t">

图5 传输门的逻辑构成图

对于利用传输门实现的三态门,分析传输门的逻辑购成可知,当S即EN为0时,传输门导通,反之,传输门的两个MOS管截止,门输出高阻态。

通过上面几种情况的介绍,希望大家能够深刻理解下面这句话:

高阻态(Z态)指的就是门的输出脚的两个驱动TTL或MOS管都处于截止状态时的输出状态。

三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t"> 

图6 文章中的所要仿真的三态总线

如图7所示,总线宽度设为4bit。WE和RE分别是读写使能信号,低有效。假设这是一个和DSP的EMIF接口的逻辑模块,在DSP写(WE=0)时,将dataInOut(EMIF)上的数据从dataOut输出;当DSP读(RE=0)时,将dataIn上的数据送到dataInOut(EMIF)上。约定WE和RE在空闲时都为高,并且二者不能同时为低。[附:DSP总线往往还有CE即片选信号,这里为简单计,略去。]

二 VHDL的三态门实现与仿真

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating

---- any Xilinx primitives in this code.

--library UNISIM;

--use UNISIM.VComponents.all;

entity vhdlTBUF is

    Port ( clk : in  STD_LOGIC;

           datain : in  STD_LOGIC_VECTOR (3 downto 0);

           dataout : out  STD_LOGIC_VECTOR (3 downto 0);

           dsta : inout  STD_LOGIC_VECTOR (3 downto 0);

           we : in  STD_LOGIC;

           re : in  STD_LOGIC);

end vhdlTBUF;

architecture Behavioral of vhdlTBUF is

begin

process(clk,we) begin

if(clk'event and clk='1') then

   if(we='0') then

            dataout<=dsta;

         end if;

end if;

end process;

--读取部分

process(clk,re) begin

if(clk'event and clk='1') then

   if(re='0') then

            dsta<=datain;

         else

            dsta<="ZZZZ";

         end if;

end if;

---================================================================

--如果期望和verilog的代码有一样的综合结果,请使用下面的话描述读取,即异步读取。

--dsta<=datain when re='0' else

--        "ZZZZ";

---================================================================

end process;

end Behavioral;

在上面的程序中可以看出,对DSP的写数据,三态逻辑模块直接将其同步锁存到寄存器中;对DSP的读数据,在RE有效时输出数据,RE无效时输出Z态。这样的实现符合图1所示的FPGA的管脚结构。

testbench:

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

USE IEEE.STD_LOGIC_TEXTIO.ALL;

USE STD.TEXTIO.ALL;

ENTITY test IS

END test;

ARCHITECTURE testbench_arch OF test IS

    FILE RESULTS: TEXT OPEN WRITE_MODE IS "results.txt";

    COMPONENT vhdlTBUF

        PORT (

            clk : In std_logic;

            datain : In std_logic_vector (3 DownTo 0);

            dataout : Out std_logic_vector (3 DownTo 0);

            dsta : InOut std_logic_vector (3 DownTo 0);

            we : In std_logic;

            re : In std_logic

        );

END COMPONENT;

    SIGNAL clk : std_logic := '0';

    SIGNAL datain : std_logic_vector (3 DownTo 0) := "0000";

    SIGNAL dataout : std_logic_vector (3 DownTo 0) := "0000";

    SIGNAL dsta : std_logic_vector (3 DownTo 0) := "ZZZZ";

    SIGNAL we : std_logic := '0';

    SIGNAL re : std_logic := '0';

    constant PERIOD : time := 200 ns;

    constant DUTY_CYCLE : real := 0.5;

    constant OFFSET : time := 100 ns;

    BEGIN

        UUT : vhdlTBUF

        PORT MAP (

            clk => clk,

            datain => datain,

            dataout => dataout,

            dsta => dsta,

            we => we,

            re => re);

        PROCESS

        BEGIN

            WAIT for OFFSET;

            CLOCK_LOOP : LOOP

                clk <= '0';

                WAIT FOR (PERIOD - (PERIOD * DUTY_CYCLE));

                clk <= '1';

                WAIT FOR (PERIOD * DUTY_CYCLE);

            END LOOP CLOCK_LOOP;

        END PROCESS;

        PROCESS

            BEGIN

                WAIT FOR 100 ns;

                we <= '1';

                re <= '1';

                datain <= "0101";               

                WAIT FOR 285 ns;

                re <= '0';               

                WAIT FOR 400 ns;

                re <= '1';               

                WAIT FOR 400 ns;

                we <= '0';

                dsta <= "0100";               

                WAIT FOR 400 ns;

                we <= '1';

                dsta <= "ZZZZ";                

                WAIT FOR 615 ns;

            END PROCESS;

END testbench_arch;

在VHDL语言里三态门仿真最重要的一点就是在初始化的时候必须将总线初始化成Z态。不仅如此,在往总线上写的时候,写数据满足要求后要立即将总线恢复成Z态,这样才不至于影响总线上的读取。原因还是如图1的FPGA管脚结构决定的。每一个总线管脚都可以看成输入和输出两部分,这里总线的初始化和赋值相当于总线的输出,即DSP的写。总线赋值如果不是Z,那么当RE=1,三态逻辑模块的输出是Z,总线即为所赋值;当RE=0时,逻辑模块输出dataIn的值,这些值如果和总线上的DSP写的值不一样,如0和1相遇,那么总线上就会出现X状态,这是我们所不期望的。

综述一句,对于VHDL语言三态门仿真,对待总线只要不是DSP写,就要将其置成Z态。

仿真和综合结果参考图7、图8和图9。从图上可以看出,同步的三态总线和异步的三态总线差别在于三态门的前面是否加了一个同步的D触发器。仿真时序图上能够清楚的看出来同步三态门的输出和时钟的同步。在实际的逻辑设计中建议尽可能使用同步逻辑。

三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t">

图7 VHDL 三态门的ModelSim仿真结果

三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t">

 图8 同步实现综合后的结果[蓝色代码] 

 三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t">

图9 异步实现综合后的结果[红色代码]

三 VerilogHDL的三态门实现与仿真

module threestategate(

    input [3:0] datain,

    output reg [3:0]  dataout,

    inout [3:0] dirdata,

    input we,

    input dspre,

    input clk

    );

   

assign dirdata=(!dspre)?datain:4'bZZZZ;

always @ (posedge(clk)) begin

if(we==1'b0)

  dataout<=dirdata;

end   

endmodule

上面的是VerilogHDL实现的三态逻辑。读取是异步的。如果期望同步的读取,修改assign语句为下面的语句:

always @ (posedge(clk)) begin

if(re==1'b0)

dirdata <= datain;

else

  dirdata <=4'bZZZZ;

end

TestBench:

`timescale 1ns/1ps

module test3z;

    reg [3:0] datain = 4'b0000;

    wire [3:0] dataout;

    reg [3:0] dirdata$inout$reg = 4'b0000;

    wire [3:0] dirdata = dirdata$inout$reg;

    reg we = 1'b0;

    reg dspre = 1'b0;

    reg clk = 1'b0;

    parameter PERIOD = 200;

    parameter real DUTY_CYCLE = 0.5;

    parameter OFFSET = 100;

    initial    // Clock process for clk

    begin

        #OFFSET;

        forever

        begin

            clk = 1'b0;

            #(PERIOD-(PERIOD*DUTY_CYCLE)) clk = 1'b1;

            #(PERIOD*DUTY_CYCLE);

        end

    end

    threestategate UUT (

        .datain(datain),

        .dataout(dataout),

        .dirdata(dirdata),

        .we(we),

        .dspre(dspre),

        .clk(clk));

    initial begin

       

        #100;

        we = 1'b1;

        dspre = 1'b1;

        datain = 4'b0101;

        dirdata$inout$reg = 4'bZZZZ;       

        #285;

        dspre = 1'b0;       

        #400;

        dspre = 1'b1;       

        #200;

        dirdata$inout$reg = 4'b0111;       

        #200;

        we = 1'b0;       

        #400;

        we = 1'b1;

        dirdata$inout$reg = 4'bZZZZ;       

    end

endmodule

在VerilogHDL语言下的三态门仿真中,很多人遇到双向总线无法写或者读的问题。这里一个关键的错误就是将dirdata在TestBench中定义成了reg或者wire。如果仅仅做这样的定义,那么dirdata要么做输入,要么做输出,自然只能仿真一种情况了。

注意看上面代码的红色部分。这里将dirdata定义为wire,自然只能够做输出了,同时定义了dirdata$inout$reg,用来做reg,是输入。通过dirdata= dirdata$inout$reg来将二者联系起来。这样,dirdata作输出,dirdata$inout$reg作输入,考虑了两个方面,完成了一个真正的双向端口。

这里有人称dirdata$inout$reg为dirdata 的“影像寄存器”,或许有道理,但是,本人认为这是从FPGA的管脚即图1所示的结构层次上的一个考虑,抓住了双向口必须同时考虑到输入和输出两个方面的关键,因此能够顺利实现仿真。

仿真和综合结果如图10和图11。

三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t">
图10 verilog双向端口仿真

三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t">

图11 verilog的异步读双向端口综合结果

四 总结

1、三态门的三态指的是除了0和1外的第三种状态。高阻态(Z态)指的就是门的输出脚的两个驱动TTL或MOS管都处于截止状态时的输出状态;

2、对于VHDL语言三态门仿真,对待总线只要不是DSP写,就要将其置成Z态;

3、在verilog中进行双向端口仿真时,将dirdata定义为wire,用作输出,同时定义了dirdata$inout$reg,定义成reg,用来作输入。通过dirdata= dirdata$inout$reg来将二者联系起来。这样,dirdata作输出,dirdata$inout$reg作输入,考虑了两个方面,完成了一个真正的双向端口,自然就能顺利仿真了。

 三态门构成 三态门原理 三态门仿真" type="#_x0000_t75" o:button="t">

韦志恒,助理研究员,工作于中科院声学所,兴趣为数字信号处理的算法研究和软硬件实现。主要从事DSP和FPGA开发。欢迎大家来我的博客!

新浪网友2010-12-01 22:23:08 [举报]


你好,找了很多关于io口的文章,发现你的最实用,已经综合出了io口,但是有个问题要向你请教:
我现在用fpga配置一个频率转换芯片,发送端每发送八位信号后需要检测接收端通过inout口送回的ack信号,如果接收成功,ack就是一个低电平,但是我把发送端和接收端中间的连线去掉,发现inout端口在做输入的时候被检测到的电平为0,这样的话当我检测ack信号的时候总是为低,很奇怪,不知道你碰到过这种情况没有

原文地址:https://www.cnblogs.com/zlh840/p/1982566.html