三态门在FPGA中的实现与仿真

三态门在数字电路上可以说是应用的非常广泛,特别是一些总线上的应用,因而,随着数字电路的发展,就避免不了用硬件描述语言在FPGA上来设计实现三态门。由于最近在玩摄像头,免不了的要写I2C协议,总线操作,就应用到了三态门,所以就在这好好总结一下三态门的设计实现及其仿真。

一.三态门在FPGA上的设计实现

首先我们要明白三态门的三态是指其输出有三种状态:高电平(逻辑1)、低电平(逻辑0)和高阻态(Hi-Z),且三态门都有个使能端EN来控制门电路的通断,其功能模型如图1-1所示:

看着图1-1,我们一眼就明白其功能的实现了,在FPGA上用硬件描述语言Verilog来描述就是这几句语句:
inout Y, //define three-state gate Y in your module
reg A; //intermediate driver registers
wire C; //Enable signal
assign Y = (C == 1’b0) ? A : 1’bz; //C control Y on-off

其实我们只要搞清楚当使能端C为低电平使能时,数据线Y作输出,其电平信号由自己内部信号决定,故用中间变量A做存储接口;当使能端C为高电平失能时,数据线作输入,其电平由外部信号决定,故为高阻态。所以,三态门的控制就在于搞清我们是要让数据线Y作输入还是作输出,一句 assign Y = (C == 1’b0) ? A : 1’bz; 即可实现,作输出时,C使能,作输入时,C失能。

二.三态门在FPGA上的仿真

三态门在FPGA上的设计实现还是比较简单的,难就难在仿真三态门的功能。以前也都练习过三态门的设计,但由于其仿真老是实现不了,也就作罢了,现如今又用到了三态门,不得不把仿真弄出来,不然心里过意不去。网上也很多这类的教程,但我认为都讲得比较含蓄,不够直白,也可能是我太笨,怎么都没理解,后面通过自己的反复练习思考,终于明白了其中的奥妙。

其实,三态门的仿真跟其设计是相通的,其测试脚本的编写刚好和硬件描述设计颠倒过来。我们首先要明白,仿真测试脚本的编写是测试我们设计的电路是否正常工作,说白点就是给我们设计的电路信号一些相应激励,设计文本里的输入信号,如clk,在测试脚本里就变成了输出,我们要产生clk这个时钟,输出给予设计文本激励,才能让设计的电路工作,进而测试其是否正常工作。总之,一句话,设计文本里的输入在测试脚本里变成输出,设计文本里的输出在测试脚本里变成输入。

明白了这个关系,我们再来说一下三态门的仿真,当设计文本里的数据线Y作输出时,测试脚本里要让Y呈高阻态,因为数据线Y此时在测试脚本里输入,设计文本驱动它输出;同理,当设计文本里的数据线Y作输入时,测试脚本里让Y通过中间变量treg_Y驱动它输出到设计文本里,使其模拟主机从机通过单总线的数据线Y进行通信。

下面给出上篇文章SCCB协议仿真的测试脚本来示范三态门测试脚本的编写,设计文本就是主机,测试脚本就是从机:

1.首先,我们知道SCCB里的单总线数据线是i2c_sdat,在测试脚本里将它定义为线网型,并定义一个寄存器型信号treg_i2c_sdat,让它作中间驱动信号,驱动i2c_sdat,具体实现如下面代码所示:
wire i2c_sdat;
reg treg_i2c_sdat = 1'b0; //treg_i2c_sdat;
// assign statements (if any)
assign i2c_sdat = treg_i2c_sdat; //treg_i2c_sdat;

2.当在设计文本里,主机要配置从机寄存器进行SCCB的写操作时,测试脚本里应将treg_i2c_sdat置为高阻态,这里测试脚本模拟从机接收主机发送的数据,测试脚本里的数据线i2c_sdat相对于设计文本作输入,测试脚本接收设计文本发送的数据,具体实现如下面代码所示:
//--------------ID_ADD------------
6'd1,6'd2,6'd3,6'd4,6'd5,6'd6,6'd7,6'd8:
begin
i2c_config_start <= 1'b1;
i2c_wr <= 1'b1; //write
i2c_config_data <= {8'haa,8'hf0,8'h55};
treg_i2c_sdat <= 1'bz; //input i2c_sdat
if(i2c_sclk_neg)
state <= state + 1'b1;
end

3.当在设计文本里,主机发送完8bit数据后等待从机应答时,测试脚本里应将treg_i2c_sdat置为0,驱动i2c_sdat输出低电平发出应答,这里测试脚本模拟从机给主机发出应答,测试脚本里的数据线i2c_sdat相对于设计文本作输出,测试脚本给设计文本发送应答,具体实现如下面代码所示:
//-----------------ACK------------------
6'd9: begin
treg_i2c_sdat <= 1'b0; //output ACK
if(i2c_sclk_neg)
state <= state + 1'b1;
end

总体上的仿真设计就是这了,可能我说的比较绕,但其中的原理各人认真思考清楚吧,具体代码自己按照我上面的三个方面模仿组织吧。

最后粘贴一张SCCB协议的仿真图,虽然上次已经用过了:

文章来源:zzuxzt的博客