非同步fifo 跨時鐘域同步(非同步FIFO)

2021-10-12 17:14:52 字數 4030 閱讀 2656

本文使用 zhihu on vscode 創作並發布

之前學習了跨時鐘域下的單bit訊號同步的方法,這些單bit訊號多是作為控制訊號或者標誌訊號來使用,再實際的專案中,處理多bit資料也是十分常見的,即資料的同步。

非同步fifo的實現其實本質上和雙口ram是一樣的,其實現思路就是將資料在src_clk的時鐘下寫入自己設定大小的ram中,然後通過讀時鐘des_clk從ram中將資料讀出來即可。

本次還是以乙個具體的例子來說明其實現,現在我們從乙個較低的時鐘域進入到乙個較高的時鐘域中,低時鐘域的資料訊號為8bit資料,現在需要將其快取,並轉換成32bit的訊號送入32位寬的匯流排上進行傳輸。具體實現**如下:

module nsync_fifo(

input src_clk,

input rst_n,

input des_clk,

input [8-1:0] fifo_data_in,

input fifo_data_in_vaild,

output reg fifo_data_out_vaild,

output [32-1:0] fifo_data_out

);// write fifo

reg [1:0] buffer_wr_addr;

reg [32-1:0] temp_buffer;

always @(posedge src_clk or negedge rst_n)

begin

if (!rst_n)

begin

buffer_wr_addr <= 2'b00;

endelse

begin

buffer_wr_addr <= (fifo_data_in_vaild) ? buffer_wr_addr + 1'b1 : buffer_wr_addr;

endendalways @(posedge src_clk)

begin

if (fifo_data_in_vaild)

begin

case(buffer_wr_addr)

2'd0:temp_buffer[0+:8] <= fifo_data_in;

2'd1:temp_buffer[8+:8] <= fifo_data_in;

2'd2:temp_buffer[16+:8] <= fifo_data_in;

2'd3:temp_buffer[24+:8] <= fifo_data_in;

endcase

endend//gen wr_fifo signal && sync

reg fifo_wr;

reg fifo_wr_sync;

wire fifo_wr_clr;

reg fifo_wr_dfb;

always @(posedge src_clk)

begin

fifo_wr <= (&buffer_wr_addr & fifo_data_in_vaild);

endassign fifo_wr_clr = !rst_n | fifo_wr_sync; // feed back

always @(posedge fifo_wr or posedge fifo_wr_clr)

begin

if (fifo_wr_clr)

begin

fifo_wr_dfb <= 1'b0;

endelse

begin

fifo_wr_dfb <= 1'b1;

endendalways @(posedge des_clk) // under des_clk sampled

begin

fifo_wr_sync <= fifo_wr_dfb;

end// recv fifo

wire recv_fifo_wr;

reg [1:0] recv_fifo_wr_addr;

assign recv_fifo_wr = fifo_wr_sync;

always @(posedge des_clk or rst_n)

begin

if (!rst_n)

begin

recv_fifo_wr_addr <= 2'b00;

endelse

begin

recv_fifo_wr_addr <= (recv_fifo_wr) ? recv_fifo_wr_addr + 1'b1 : recv_fifo_wr_addr;

endend// sync fifo data

reg [32-1:0] fifo_0;

reg [32-1:0] fifo_1;

always @(posedge des_clk)

begin

if (recv_fifo_wr) // only buffer_wr_addr == 3 gen

begin

case (recv_fifo_wr_addr[0])

1'b0 : fifo_0 <= temp_buffer;

1'b1 : fifo_1 <= temp_buffer;

endcase

endend// read data from recv fifo

wire [1:0] recv_fifo_cnt;

wire recv_fifo_full;

wire recv_fifo_ready;

reg [1:0] recv_fifo_rd_addr;

assign recv_fifo_ready = | recv_fifo_cnt;

assign recv_fifo_full = recv_fifo_cnt[1]; // 2'b11 = 3

assign recv_fifo_cnt = recv_fifo_wr_addr - recv_fifo_rd_addr;

always @(posedge des_clk or negedge rst_n)

begin

if (!rst_n)

begin

recv_fifo_rd_addr <= 2'b00;

endelse

begin

recv_fifo_rd_addr <= (recv_fifo_ready) ? recv_fifo_rd_addr + 1'b1 : recv_fifo_rd_addr;

endendreg [32-1:0] recv_fifo_data;

always @(*)

begin

case(recv_fifo_rd_addr[0])

1'b0 : recv_fifo_data = fifo_0;

1'b1 : recv_fifo_data = fifo_1;

endcase

end// out

assign fifo_data_out = recv_fifo_data;

always @(posedge des_clk or negedge rst_n)

begin

if(!rst_n)

begin

fifo_data_out_vaild <= 1'b0;

endelse

begin

fifo_data_out_vaild <= recv_fifo_ready;

endendendmodule

從上面的**可以發現,我這裡將src_clk中的寫訊號fifo_wr通過上章講解的單bit反饋同步方法同步到了des_clk的時鐘域下fifo_wr_sync;這樣後續的訊號處理造作就可以在我們的目標時鐘des_clk下進行操作了。因為這裡需要快取的資料很少,位址線就顯得比較簡單了,通過乙個簡單的桌球操作不斷將資料從buffer中寫入fifo_0和fifo_1中;只要fifo不空,就開始讀資料。時序如下:

非同步fifo 同步FIFO設計實現

在學習跨時鐘域處理的時候,有一種方法是用非同步fifo來處理跨時鐘域處理的。那麼在這之前先看看同步fifo實現。所謂同步fifo,就是讀寫時鐘是同乙個時鐘頻率。本次實現是通過計數器的形式來實現滿空標誌。具體實現如下 module fifo sync input clk input rst n inp...

FIFO跨時鐘域讀寫

今天面試,要走時問了我乙個問題 如果兩個時鐘乙個時鐘慢乙個時鐘快,來讀寫fifo,其中讀出的資料是 連續的一段一段的。圖1 圖1為寫時序控制,可以看出資料是兩個時鐘週期的長度,當然實際中可以是任意週期的長度。圖2 圖2為讀時序,ren使能的長度也可以是任意,但是我以為一點是必須保證的,那就是讀寫資料...

FPGA基礎知識14 跨時鐘域處理 非同步時鐘

需求說明 ic設計基礎 內容 第一部分 fpga跨時鐘域的處理方法 第二部分 基於fpga的跨時鐘域訊號處理 專用握手訊號 來自 時間的詩 原文 在乙個 fpga 系統設計中,經常需要處理多個時鐘 比如fpga作為乙個 橋連線幾個不同的ic。不同的時鐘域有不同的時鐘頻率和時鐘相位。如何處理好多個時鐘...