今天要介紹的異步FIFO,可以有不同的讀寫時(shí)鐘,即不同的時(shí)鐘域。由于異步FIFO沒(méi)有外部地址端口,因此內(nèi)部采用讀寫指針并順序讀寫,即先寫進(jìn)FIFO的數(shù)據(jù)先讀?。ê?jiǎn)稱先進(jìn)先出)。這里的讀寫指針是異步的,處理不同的時(shí)鐘域,而異步FIFO的空滿標(biāo)志位是根據(jù)讀寫指針的情況得到的。
為了得到正確的空滿標(biāo)志位,需要對(duì)讀寫指針進(jìn)行同步。一般情況下,如果一個(gè)時(shí)鐘域的信號(hào)直接給另一個(gè)時(shí)鐘域采集,可能會(huì)產(chǎn)生亞穩(wěn)態(tài),亞穩(wěn)態(tài)的產(chǎn)生對(duì)設(shè)計(jì)而言是致命的。為了減少不同時(shí)鐘域間的亞穩(wěn)態(tài)問(wèn)題,我們先對(duì)它進(jìn)行兩拍寄存同步,如圖1所示。
當(dāng)然,對(duì)異步信號(hào)的寄存越多,產(chǎn)生亞穩(wěn)態(tài)的概率就越小,但延時(shí)越多。不過(guò)一般情況下,寄存兩拍就夠了。為了繼續(xù)減少亞穩(wěn)態(tài)產(chǎn)生的概率,在對(duì)異步信號(hào)同步之前,將其轉(zhuǎn)換為格雷碼,使其每個(gè)狀態(tài)只有一個(gè)位在變化。例如,假設(shè)N位二進(jìn)制變量產(chǎn)生的亞穩(wěn)態(tài)概率為a,那么二進(jìn)制轉(zhuǎn)換成格雷碼后其產(chǎn)生的亞穩(wěn)態(tài)概率則為a/N。
圖1 對(duì)異步信號(hào)用兩級(jí)寄存器同步
根據(jù)上述原理,設(shè)計(jì)了異步FIFO的架構(gòu),如圖2所示。
圖2 異步FIFO設(shè)計(jì)架構(gòu)
根據(jù)異步FIFO的設(shè)計(jì)架構(gòu),歸納以下設(shè)計(jì)步驟:
寫時(shí)鐘域:
(1)根據(jù)寫使能wr_en和寫滿標(biāo)志位wr_full產(chǎn)生二進(jìn)制寫指針
(2)根據(jù)二進(jìn)制寫指針產(chǎn)生雙端口RAM的寫地址
(3)由二進(jìn)制寫指針轉(zhuǎn)換成格雷碼寫指針
(4)對(duì)格雷碼讀指針在寫時(shí)鐘域中進(jìn)行兩級(jí)同步得同步后格雷碼讀指針
(5)同步后格雷碼讀指針轉(zhuǎn)化成同步后二進(jìn)制讀指針
(6)步驟(3)與步驟(4)比較得寫滿標(biāo)志位wr_full
(7)步驟(1)與步驟(5)相減得指示寫FIFO的數(shù)據(jù)量
讀時(shí)鐘域:
(8)根據(jù)讀使能rd_en和讀空標(biāo)志位rd_empty產(chǎn)生二進(jìn)制讀指針
(9)根據(jù)二進(jìn)制讀指針產(chǎn)生雙端口RAM的讀地址
(10)由二進(jìn)制讀指針轉(zhuǎn)換成格雷碼讀指針
(11)對(duì)格雷碼寫指針在讀時(shí)鐘域中進(jìn)行兩級(jí)同步得同步后格雷碼寫指針
(12)同步后格雷碼寫指針轉(zhuǎn)化成同步后二進(jìn)制寫指針
(13)步驟(10)與步驟(11)比較得讀空標(biāo)志位rd_empty
(14)步驟(8)與步驟(12)相減得指示讀FIFO的數(shù)據(jù)量
Verilog HDL設(shè)計(jì)電路,如下所示:
**------------------------------文件信息--------------------------------
** 文件名: asyn_fifo.v
** 創(chuàng)建者: CrazyBird
** 創(chuàng)建日期: 2016-1-16
** 版本號(hào): v1.0
** 功能描述: 異步FIFO,用于處理不同的時(shí)鐘域
**
***********************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module asyn_fifo(
wr_rst_n,
wr_clk,
wr_en,
wr_data,
wr_full,
wr_cnt,
rd_rst_n,
rd_clk,
rd_en,
rd_data,
rd_empty,
rd_cnt
);
//******************************************************************
// 參數(shù)定義
//******************************************************************
parameter C_DATA_WIDTH = 8;
parameter C_FIFO_DEPTH_WIDTH = 4;
//******************************************************************
// 端口定義
//******************************************************************
input wr_rst_n;
input wr_clk;
input wr_en;
input [C_DATA_WIDTH-1:0] wr_data;
output reg wr_full;
output reg [C_FIFO_DEPTH_WIDTH:0] wr_cnt;
input rd_rst_n;
input rd_clk;
input rd_en;
output [C_DATA_WIDTH-1:0] rd_data;
output reg rd_empty;
output reg [C_FIFO_DEPTH_WIDTH:0] rd_cnt;
//******************************************************************
// 內(nèi)部變量定義
//******************************************************************
reg [C_DATA_WIDTH-1:0] mem [0:(1 《《 C_FIFO_DEPTH_WIDTH)-1];
wire [C_FIFO_DEPTH_WIDTH-1:0] wr_addr;
wire [C_FIFO_DEPTH_WIDTH-1:0] rd_addr;
wire [C_FIFO_DEPTH_WIDTH:0] next_wr_bin_ptr;
wire [C_FIFO_DEPTH_WIDTH:0] next_rd_bin_ptr;
reg [C_FIFO_DEPTH_WIDTH:0] wr_bin_ptr;
reg [C_FIFO_DEPTH_WIDTH:0] rd_bin_ptr;
wire [C_FIFO_DEPTH_WIDTH:0] next_wr_gray_ptr;
wire [C_FIFO_DEPTH_WIDTH:0] next_rd_gray_ptr;
wire [C_FIFO_DEPTH_WIDTH:0] syn_wr_bin_ptr_rd_clk;
wire [C_FIFO_DEPTH_WIDTH:0] syn_rd_bin_ptr_wr_clk;
wire [C_FIFO_DEPTH_WIDTH:0] syn_wr_gray_ptr_rd_clk;
wire [C_FIFO_DEPTH_WIDTH:0] syn_rd_gray_ptr_wr_clk;
wire [C_FIFO_DEPTH_WIDTH:0] wr_cnt_w;
wire [C_FIFO_DEPTH_WIDTH:0] rd_cnt_w;
wire wr_full_w;
wire rd_empty_w;
//******************************************************************
// 雙端口RAM的讀寫
//******************************************************************
// 寫RAM
always @(posedge wr_clk)
begin
if((wr_en & ~wr_full) == 1‘b1)
mem[wr_addr] 《= wr_data;
end
// 讀RAM
assign rd_data = mem[rd_addr];
//******************************************************************
// 二進(jìn)制寫指針的產(chǎn)生
//******************************************************************
assign next_wr_bin_ptr = wr_bin_ptr + (wr_en & ~wr_full);
always @(posedge wr_clk or negedge wr_rst_n)
begin
if(wr_rst_n == 1’b0)
wr_bin_ptr 《= {(C_FIFO_DEPTH_WIDTH+1){1‘b0}};
else
wr_bin_ptr 《= next_wr_bin_ptr;
end
//******************************************************************
// RAM寫地址的產(chǎn)生
//******************************************************************
assign wr_addr = wr_bin_ptr[C_FIFO_DEPTH_WIDTH-1:0];
//******************************************************************
// 二進(jìn)制寫指針轉(zhuǎn)換成格雷碼寫指針
//******************************************************************
bin2gray #(
.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)
)
u_bin2gray_wr (
.bin ( next_wr_bin_ptr ),
.gray ( next_wr_gray_ptr )
);
//******************************************************************
// 對(duì)格雷碼讀指針在寫時(shí)鐘域中進(jìn)行兩級(jí)同步
//******************************************************************
double_syn_ff #(
.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)
)
u_double_syn_ff_wr (
.rst_n ( wr_rst_n ),
.clk ( wr_clk ),
.din ( next_rd_gray_ptr ),
.dout ( syn_rd_gray_ptr_wr_clk )
);
//******************************************************************
// 同步后的格雷碼讀指針轉(zhuǎn)換成同步后的二進(jìn)制讀指針
//******************************************************************
gray2bin #(
.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)
)
u_gray2bin_wr (
.gray ( syn_rd_gray_ptr_wr_clk ),
.bin ( syn_rd_bin_ptr_wr_clk )
);
//******************************************************************
// FIFO寫滿標(biāo)志位的產(chǎn)生和寫FIFO數(shù)據(jù)量的計(jì)數(shù)
//******************************************************************
assign wr_full_w = (next_wr_gray_ptr == ({~syn_rd_gray_ptr_wr_clk[C_FIFO_DEPTH_WIDTH:C_FIFO_DEPTH_WIDTH-1],
syn_rd_gray_ptr_wr_clk[C_FIFO_DEPTH_WIDTH-2:0]}));
assign wr_cnt_w = next_wr_bin_ptr - syn_rd_bin_ptr_wr_clk;
always @(posedge wr_clk or negedge wr_rst_n)
begin
if(wr_rst_n == 1’b0)
begin
wr_full 《= 1‘b0;
wr_cnt 《= {(C_FIFO_DEPTH_WIDTH+1){1’b0}};
end
else
begin
wr_full 《= wr_full_w;
wr_cnt 《= wr_cnt_w;
end
end
//******************************************************************
// 二進(jìn)制讀指針的產(chǎn)生
//******************************************************************
assign next_rd_bin_ptr = rd_bin_ptr + (rd_en & ~rd_empty);
always @(posedge rd_clk or negedge rd_rst_n)
begin
if(rd_rst_n == 1‘b0)
rd_bin_ptr 《= {(C_FIFO_DEPTH_WIDTH+1){1’b0}};
else
rd_bin_ptr 《= next_rd_bin_ptr;
end
//******************************************************************
// RAM讀地址的產(chǎn)生
//******************************************************************
assign rd_addr = rd_bin_ptr[C_FIFO_DEPTH_WIDTH-1:0];
//******************************************************************
// 二進(jìn)制讀指針轉(zhuǎn)換成格雷碼讀指針
//******************************************************************
bin2gray #(
.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)
)
u_bin2gray_rd (
.bin ( next_rd_bin_ptr ),
.gray ( next_rd_gray_ptr )
);
//******************************************************************
// 對(duì)格雷碼寫指針在讀時(shí)鐘域中進(jìn)行兩級(jí)同步
//******************************************************************
double_syn_ff #(
.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)
)
u_double_syn_ff_rd (
.rst_n ( rd_rst_n ),
.clk ( rd_clk ),
.din ( next_wr_gray_ptr ),
.dout ( syn_wr_gray_ptr_rd_clk )
);
//******************************************************************
// 同步后的格雷碼寫指針轉(zhuǎn)換成同步后的二進(jìn)制寫指針
//******************************************************************
gray2bin #(
.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)
)
u_gray2bin_rd (
.gray ( syn_wr_gray_ptr_rd_clk ),
.bin ( syn_wr_bin_ptr_rd_clk )
);
//******************************************************************
// FIFO讀空標(biāo)志位的產(chǎn)生和讀FIFO數(shù)據(jù)量的計(jì)數(shù)
//******************************************************************
assign rd_empty_w = (next_rd_gray_ptr == syn_wr_gray_ptr_rd_clk);
assign rd_cnt_w = syn_wr_bin_ptr_rd_clk - next_rd_bin_ptr;
always @(posedge rd_clk or negedge rd_rst_n)
begin
if(rd_rst_n == 1‘b0)
begin
rd_empty 《= 1’b0;
rd_cnt 《= {(C_FIFO_DEPTH_WIDTH+1){1‘b0}};
end
else
begin
rd_empty 《= rd_empty_w;
rd_cnt 《= rd_cnt_w;
end
end
endmodule
其中,模塊gray2bin是格雷碼轉(zhuǎn)二進(jìn)制碼,模塊bin2gray是二進(jìn)制碼轉(zhuǎn)格雷碼,詳情見上一篇博客,地址:http://blog.chinaaet.com/crazybird/p/5100000866 。模塊double_syn_ff是兩級(jí)寄存器,用于同步信號(hào),對(duì)應(yīng)的Verilog HDL實(shí)現(xiàn)如下所示:
**------------------------------文件信息--------------------------------
** 文件名: double_syn_ff.v
** 創(chuàng)建者: CrazyBird
** 創(chuàng)建日期: 2016-1-16
** 版本號(hào): v1.0
** 功能描述: 對(duì)輸入信號(hào)進(jìn)行兩級(jí)同步后輸出
**
***********************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module double_syn_ff(
rst_n,
clk,
din,
dout
);
//******************************************************************
// 參數(shù)定義
//******************************************************************
parameter C_DATA_WIDTH = 8;
//******************************************************************
// 端口定義
//******************************************************************
input rst_n;
input clk;
input [C_DATA_WIDTH-1:0] din;
output reg [C_DATA_WIDTH-1:0] dout;
//******************************************************************
// 內(nèi)部變量定義
//******************************************************************
reg [C_DATA_WIDTH-1:0] data_r;
//******************************************************************
// 對(duì)輸入信號(hào)進(jìn)行兩級(jí)同步后輸出
//******************************************************************
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1’b0)
{dout,data_r} 《= {(2*C_DATA_WIDTH){1‘b0}};
else
{dout,data_r} 《= {data_r,din};
end
endmodule
由于字?jǐn)?shù)的限制,異步FIFO的功能驗(yàn)證放在下一篇博文中吧!??!
-
寄存器
+關(guān)注
關(guān)注
31文章
5355瀏覽量
120535 -
fifo
+關(guān)注
關(guān)注
3文章
389瀏覽量
43704
原文標(biāo)題:【原創(chuàng)博文】基于FPGA的異步FIFO設(shè)計(jì)
文章出處:【微信號(hào):ChinaAET,微信公眾號(hào):電子技術(shù)應(yīng)用ChinaAET】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論