FPGA基础知识极简教程(8)详解三态缓冲器
博⽂⽬录
写在前⾯
下⾯⽤举例⼦的⽅式引出三态门,内容过长,⼤家可直接跳过,进⼊正⽂!
三态门在FPGA以及ASIC设计中⼗分常⽤,随便举⼀个例⼦,在RAM的设计中(⽆论是同步读写RAM还是异步读写RAM设计),我们常将数据总线设计成inout类型,下⾯是⼀个设计程序实例:
`timescale 1ns /1ps
//
// Engineer: Reborn Lee
// Module Name: single_port_syn_ram
/
module single_port_syn_ram#(
parameter ADDR_WIDTH =4,
parameter DATA_WIDTH =16,
parameter DEPTH =2**ADDR_WIDTH
)(
input i_clk,
input [ADDR_WIDTH -1:0] addr,
inout [DATA_WIDTH -1:0] data,
input cs,
input wr,
input oe
);
reg [DATA_WIDTH -1:0] mem[0: DEPTH -1];
reg [DATA_WIDTH -1:0] mid_data;
// write part
always@(podge i_clk) begin
if(cs&wr) begin
mem[addr]<= data;
end
end
// read part
always@(podge i_clk) begin
if(cs &!wr) begin
mid_data <= mem[addr];
end
end
assign data =(cs & oe &!wr)? mid_data: 'hz;
endmodule
在读数据的时候,我们需要设计⼀个三态缓冲器,如下:
assign data =(cs & oe &!wr)? mid_data: 'hz;
读使能有效时,我们将从缓冲区读出的数据放到mid_data中,之后通过⼀个三态门来将数据mid_data输出到三态总线上,此三态门的使能条件为读使能!
这条语句在综合⼯具中就会被推断为⼀个三态缓冲器!
在读使能有效时,将读取数据放在总线上,否则呈现为⾼阻态,避免占⽤此数据总线。
在testbench⽂件中,我们同样需要作出类似的操作,如下针对上⾯的ram的测试⽂件:
`timescale 1ns /1ps
///
// Engineer: Reborn Lee
// Module Name: ram_tb
//
module ram_tb(
);
parameter ADDR_WIDTH =4;
parameter DATA_WIDTH =16;
parameter DEPTH =2**ADDR_WIDTH;
reg i_clk;
reg [ADDR_WIDTH -1:0] addr;
wire [DATA_WIDTH -1:0] data;
reg cs;
reg wr;
reg oe;
reg [DATA_WIDTH-1:0] tb_data;
//generate system clock
initial begin
i_clk =0;
forever begin
# 5 i_clk =~i_clk;
end
end
assign data =!oe ? tb_data : 'hz;
initial begin
{cs, wr, addr, tb_data, oe}=0;
repeat (2) @ (podge i_clk);
//write test
for(integer i =0; i <2**ADDR_WIDTH; i= i+1) begin
repeat (1) @(negedge i_clk) addr = i; wr =1; cs =1; oe =0; tb_data = $random;
end
//read test
repeat (2) @ (podge i_clk);
for(integer i =0; i <2**ADDR_WIDTH; i= i+1) begin
repeat (1) @(podge i_clk) addr = i; wr =0; cs =1; oe =1;
end
#20 $finish;
end
single_port_syn_ram #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH),
.DEPTH(DEPTH)
) inst_single_port_syn_ram (
.
i_clk (i_clk),
.addr (addr),
.addr (addr),
.data (data),
.cs (cs),
.wr (wr),
.oe (oe)
);
endmodule
由于inout端⼝在测试⽂件中必须设置为wire类型,因此,我们在设计写数据时,需要定义⼀个中间reg类型变量,这个变量在写使能有效时候输⼊给写数据端⼝,如下:
assign data =!oe ? tb_data : 'hz;
否则,也就是写使能⽆效时,就为⾼阻态,不占⽤数据总线!
注:上⾯⽤了oe⽆效代替写使能有效,有点不太严谨,但也没问题 ,仅供各位参考!
个⼈微信公众号: FPGA LAB
注:学习交流使⽤!
正⽂
三态缓冲器可以处于以下三种状态之⼀:逻辑0,逻辑1和Z(⾼阻抗)。它们的使⽤允许多个驱动程序共享⼀条公共线路。这使得它们在半双⼯通信中特别有⽤。让我们⾸先讨论半双⼯和全双⼯通信之间的区别。
全双⼯与半双⼯
全双⼯和半双⼯的区别可以使⽤下⾯的两幅图来说明:
在全双⼯系统中,有两个路径⽤于在两个芯⽚之间发送数据。从芯⽚1到芯⽚2有⼀条专⽤路径,从芯⽚2到芯⽚1有⼀条专⽤路径。在半双⼯系统中,只有⼀条路径可以在两个芯⽚之间发送数据。因此,
这两个芯⽚必须在要传输的对象上达成共识。如果两者尝试同时传输,则线路上将发⽣冲突,并且数据将丢失。
在以上两个图中,三⾓形是您的缓冲区。注意,在半双⼯框图中,存在信号Tx En。这是控制三态发
送缓冲器的信号。在全双⼯块图中,此信号不是必需的,因为两个发送器都可以在100%的时间内打开,⽽不会在线路上发⽣冲突。
FPGA和ASIC中的三态缓冲器
如下为三态缓冲器的真值表:
Tx Data Tx Enable Output
010
111
X0Z (high impedance)
请注意,如果两个Tx En同时都为⾼,则两个发送器都将在驱动并且线路上将发⽣冲突。 使⽤半双⼯三态缓冲器时,⾄关重要的是,共享线路的模块必须制定出⼀种避免数据冲突的通信⽅案。
如何在VHDL和Verilog中推断出三态缓冲区
综合⼯具可以推断出三态缓冲器。这是在VHDL中推断三态缓冲区的⽅法。信号io_data 在实体的端⼝
映射部分中声明为inout。在VHDL 中,“ Z”为⾼阻抗。
inout io_data : std_logic;--port declaration of bidirectional data line
io_data <= w_Tx_Data when w_Tx_En ='1'el'Z';
w_Rx_Data <= io_data;
这是在Verilog中推断三态缓冲区的⽅法。信号io_data 在模块的端⼝声明部分中声明为inout。在Verilog中,1’bZ是⾼阻抗。
inout io_data;//port declaration of bidirectional data line
assign io_data = Tx_En ? Tx_Data :1'bZ;
assign Rx_Data = io_data;
三态缓冲器常⽤于半双⼯UART和I2C接⼝等电路中。它们是数字设计师了解的⾮常有⽤的⼯具。您应该知道如何在VHDL和Verilog中推断三态缓冲区。
参考资料
交个朋友
个⼈微信公众号:FPGA LAB
知乎:李锐博恩