本文使用 zhihu on vscode 創作並發布
之前學習了跨時鐘域下的單bit訊號同步的方法,這些單bit訊號多是作為控制訊號或者標誌訊號來使用,再實際的專案中,處理多bit資料也是十分常見的,即資料的同步。
非同步fifo的實現其實本質上和雙口ram是一樣的,其實現思路就是將資料在src_clk的時鐘下寫入自己設定大小的ram中,然後通過讀時鐘des_clk從ram中將資料讀出來即可。
本次還是以乙個具體的例子來說明其實現,現在我們從乙個較低的時鐘域進入到乙個較高的時鐘域中,低時鐘域的資料訊號為8bit資料,現在需要將其快取,並轉換成32bit的訊號送入32位寬的匯流排上進行傳輸。具體實現**如下:
從上面的**可以發現,我這裡將src_clk中的寫訊號fifo_wr通過上章講解的單bit反饋同步方法同步到了des_clk的時鐘域下fifo_wr_sync;這樣後續的訊號處理造作就可以在我們的目標時鐘des_clk下進行操作了。因為這裡需要快取的資料很少,位址線就顯得比較簡單了,通過乙個簡單的桌球操作不斷將資料從buffer中寫入fifo_0和fifo_1中;只要fifo不空,就開始讀資料。時序如下: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
非同步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。不同的時鐘域有不同的時鐘頻率和時鐘相位。如何處理好多個時鐘...