閱讀本文前,建議先閱讀下面幾篇文章:
同步FIFO
二進(jìn)制轉(zhuǎn)格雷碼的實(shí)現(xiàn)
前言
??在上篇文章同步FIFO中簡(jiǎn)要介紹了FIFO的基本概念以及同步FIFO的實(shí)現(xiàn)。本篇文章將重點(diǎn)介紹異步FIFO的工作原理以及硬件實(shí)現(xiàn)。
異步FIFO的工作原理
1. 概述
??異步FIFO的讀寫時(shí)鐘不同,F(xiàn)IFO的讀寫需要進(jìn)行異步處理,異步FIFO常用于多bit數(shù)據(jù)跨時(shí)鐘域處理。異步FIFO一般有復(fù)位rst_n、讀端口和寫端口。讀端口一般包括讀時(shí)鐘(rd_clk)、讀使能(rd_en)、讀數(shù)據(jù)(data_out)、讀空(empty)。寫端口一般包括寫時(shí)鐘(wr_clk)、寫使能(wr_en)、寫數(shù)據(jù)(data_in)、寫滿(wr_full)。
2. 地址的跨時(shí)鐘問題
??實(shí)現(xiàn)異步FIFO難點(diǎn)仍在于如何得到讀空和寫滿信號(hào)。由于異步FIFO的讀寫具有不同的時(shí)鐘,讀寫?yīng)毩ⅲ强諠M信號(hào)的判決仍需要通過讀寫地址(多bit數(shù)據(jù))來實(shí)現(xiàn),這里涉及到了多bit數(shù)據(jù)的跨時(shí)鐘域處理,當(dāng)然這里無法使用異步FIFO來實(shí)現(xiàn)這個(gè)跨時(shí)鐘處理,畢竟我們就是為了做異步FIFO。多bit跨時(shí)鐘處理還可以通過改變編碼方式來降低亞穩(wěn)態(tài)的發(fā)生概率。當(dāng)讀地址由4’b0111向4’b1000變化時(shí),所有位都需要變化,如果寫時(shí)鐘恰好在地址變化時(shí)采樣,寫時(shí)鐘得到的讀地址是不確定的(為0000~1111中任意一個(gè)),因此為了降低該亞穩(wěn)態(tài)的發(fā)生概率,地址采用格雷碼編碼。格雷碼每次只變化一位,可以有效降低亞穩(wěn)態(tài)的發(fā)生概率,同時(shí)單bit又可以采用打兩拍的方法再次降低亞穩(wěn)態(tài)發(fā)生的概率。
??綜上所述,為有效解決地址的跨時(shí)鐘問題,采取格雷碼編碼+打兩拍的方式降低地址變化發(fā)生亞穩(wěn)態(tài)的概率。二進(jìn)制轉(zhuǎn)格雷碼的實(shí)現(xiàn)。
3. 空滿信號(hào)的判決條件
??由于異步FIFO的讀寫地址采用格雷碼,空滿信號(hào)的判決條件不同于同步FIFO。同同步FIFO,可以將讀寫地址擴(kuò)展一位,用于判斷是否讀寫完一輪,即深度為8,地址為4bit。以下為深度為8的異步FIFO進(jìn)行讀寫情況,以下只列舉了四種操作,其余讀寫少于深度個(gè)數(shù)據(jù)的情況也是類似的。
??綜上所述,讀空empty信號(hào)拉高的判決條件是讀寫地址的格雷碼相同。寫滿信號(hào)拉高的判決條件是讀寫地址的格雷碼的高2位不同,其余位相同。
??但是上述判決條件可能存在一些問題。由于讀寫地址需要打兩拍,如果打拍期間還有讀寫操作,那讀寫地址又改變了,得到的并不是真正的空滿信號(hào),那會(huì)出現(xiàn)數(shù)據(jù)丟失的情況嗎?舉例說明如下:文章來源:http://www.zghlxwxcb.cn/news/detail-759219.html
- 判斷空信號(hào):判斷空信號(hào),需要比較rd_clk的讀地址rd_addr和從wr_clk打拍到rd_clk的寫地址wr_addr_w2r,如果在打拍過程中,還寫入數(shù)據(jù)(wr_addr增加),那么用于判斷空信號(hào)的wr_addr_w2r會(huì)小于實(shí)際的寫地址wr_addr。如果此時(shí)判斷為空,其實(shí)FIFO并不是真空,只不過此時(shí)FIFO不能再讀出數(shù)據(jù),此種情況并不會(huì)發(fā)生數(shù)據(jù)丟失。并且下一個(gè)時(shí)鐘,空信號(hào)便會(huì)失效,并不會(huì)影響FIFO的正常使用。
- 判斷滿信號(hào):判斷滿信號(hào),需要比較wr_clk的寫地址wr_addr和從rd_clk打拍到wr_clk的讀地址rd_addr_r2w,如果在打拍過程中,還讀出數(shù)據(jù)(rd_addr增加),那么用于判斷滿信號(hào)的rd_addr_r2w會(huì)小于實(shí)際的讀地址rd_addr。如果此時(shí)判斷為滿,其實(shí)FIFO并不是真滿,只不過此時(shí)FIFO不能再寫入數(shù)據(jù),此種情況并不會(huì)發(fā)生數(shù)據(jù)丟失。并且下一個(gè)時(shí)鐘,滿信號(hào)便會(huì)失效,并不會(huì)影響FIFO的正常使用。
異步FIFO的實(shí)現(xiàn)
module async_fifo#(
parameter DEPTH = 16,
parameter WIDTH = 8,
parameter ADDR_BIT = 4, //log2(DEPTH)
parameter RAM_STYLE_VAL = "distributed"
)(
input wr_clk,
input rst_n,
input wr_en,
input [WIDTH-1:0] data_in,
input rd_clk,
input rd_en,
output [WIDTH-1:0] data_out,
output full,
output empty
);
(*ram_style=RAM_STYLE_VAL*)
reg [WIDTH-1:0] mem [DEPTH-1:0];
reg [WIDTH-1:0] data_out_r;
reg [ADDR_BIT:0] wr_addr;
wire [ADDR_BIT:0] wr_addr_gray;
reg [ADDR_BIT:0] wr_addr_w2r1;
reg [ADDR_BIT:0] wr_addr_w2r2;
reg [ADDR_BIT:0] rd_addr;
wire [ADDR_BIT:0] rd_addr_gray;
reg [ADDR_BIT:0] rd_addr_r2w1;
reg [ADDR_BIT:0] rd_addr_r2w2;
//*********************** Address ***********************//
//write address
always @ (posedge wr_clk or negedge rst_n)begin
if(!rst_n) wr_addr <= 'd0;
else if(wr_en) wr_addr <= wr_addr + 1;
else wr_addr <= wr_addr;
end
//write address - > gray
assign wr_addr_gray = (wr_addr>>1)^wr_addr;
//Write address synchronization to read clock domain
always @ (posedge wr_clk or negedge rst_n)begin
if(!rst_n)
{wr_addr_w2r2,wr_addr_w2r1} <= 'd0;
else
{wr_addr_w2r2,wr_addr_w2r1} <= {wr_addr_w2r1,wr_addr_gray};
end
//read address
always @ (posedge rd_clk or negedge rst_n)begin
if(!rst_n)
rd_addr <= 'd0;
else if(rd_en)
rd_addr <= rd_addr + 1;
else
rd_addr <= rd_addr;
end
//write address - > gray
assign rd_addr_gray = (rd_addr>>1)^rd_addr;
//Read address synchronization to write clock domain
always @ (posedge rd_clk or negedge rst_n)begin
if(!rst_n)
{rd_addr_r2w2,rd_addr_r2w1} <= 'd0;
else
{rd_addr_r2w2,rd_addr_r2w1} <= {rd_addr_r2w1,rd_addr_gray};
end
//************************* Data *************************//
//write data
always @ (posedge wr_clk)begin
if(wr_en)
mem[wr_addr] <= data_in;
else
mem[wr_addr] <= mem[wr_addr];
end
//read data delay 1clk
assign data_out = data_out_r;
always @ (posedge rd_clk or negedge rst_n)begin
if(!rst_n)
data_out_r <= {WIDTH{1'b0}};
else if(rd_en==1)
data_out_r <= mem[rd_addr];
else
data_out_r <= data_out_r;
end
//********************** Full/Empty *********************//
//Empty signal judgment
assign empty = (wr_addr_w2r2 == rd_addr_gray);
//Full signal judgment
assign full = ({~(rd_addr_r2w2[4:3]),rd_addr_r2w2[2:0]}==wr_addr_gray[4:0]);
endmodule
異步FIFO的仿真測(cè)試
module tb_async;
reg wr_clk,rd_clk;
reg rst_n;
reg wr_en;
reg rd_en;
reg [7:0] data_in;
wire [7:0] data_out;
wire full;
wire empty;
parameter WR_PERIOD = 10;
parameter RD_PERIOD = 20 ;
async_fifo async_fifo(
.wr_clk (wr_clk ),
.rst_n (rst_n ),
.wr_en (wr_en ),
.data_in (data_in ),
.rd_clk (rd_clk ),
.rd_en (rd_en ),
.data_out (data_out ),
.full (full ),
.empty (empty )
);
initial begin
wr_clk = 0;rd_clk=0;rst_n = 0;
wr_en <= 0;rd_en <= 0;data_in = 'd0;
#15 rst_n = 1;
write_data(16);
#100
read_data(16);
#100
$finish;
end
always # (WR_PERIOD/2) wr_clk = ~wr_clk;
always # (RD_PERIOD/2) rd_clk = ~rd_clk;
task write_data(input [7:0] t);
begin
repeat(t)begin
@(posedge wr_clk)
data_in <= {$random}%256;
wr_en <= 1;
end
@(posedge wr_clk) wr_en <= 0;data_in <= 'd0;
end
endtask
task read_data(input [7:0] t);
integer i;
begin
repeat(t)begin
@(posedge rd_clk)
rd_en <= 1;
end
@(posedge rd_clk) rd_en <= 0;
end
endtask
endmodule
??仿真結(jié)果如下,可以發(fā)現(xiàn)該異步fifo邏輯正確。文章來源地址http://www.zghlxwxcb.cn/news/detail-759219.html
到了這里,關(guān)于FPGA的Verilog設(shè)計(jì)(二)——異步FIFO的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!