1. 程式人生 > 其它 >同步FIFO設計程式碼實現

同步FIFO設計程式碼實現

  FIFO類似於一根管道,先進的資料先出。FIFO的要點在於對於寫滿和讀空的判斷,而寫滿與讀空的判斷又依賴於讀指標/讀地址暫存器和寫指標/寫地址暫存器的比較。

  一組遞增的讀/寫指標用來實現先寫的資料先被讀出。初始時,讀寫指標都為0,即指向雙埠Memory的同一地址,每一次FIFO寫動作都會將資料寫入當前寫指標對應的儲存器地址,然後寫指標加1,指向一個新的未寫的Memory空間;每次讀動作,FIFO當前的讀指標對應的資料將會被讀出,然後讀指標加1,指向下一個待讀資料的地址空間。

  一開始寫指標和讀指標都為0,當寫入時,寫指標增加,當讀出時,讀指標增加,指標範圍為0~DEPTH-1。當寫指標和讀指標相同時,可能為讀空狀態,也可能為寫完一輪的寫滿狀態;
  為了判斷究竟是寫滿狀態還是讀空狀態,可以設定一個計數器,當每寫入一個數據時,計數器加1,每讀出一個數據時,計數器減1。這樣,當計數器為0時,說明資料都已經被讀完了,為讀空狀態,當計數器等於管道深度時,說明寫比讀多了一輪,為寫滿狀態。
注意,讀寫指標指向的都是下一個要寫/讀的資料,意思是說寫指標為2時,說明第0,1個數據已經寫入了,下一個要寫入的資料是第二個。

 

 

  同步FIFO的時鐘復位共用,並定義寫入和讀出埠:

 

接著定義RAM,計數器、讀寫指標:

 

 $clog2函式為以2為底求對數函式,當資料深度為8時,讀寫指標為3位。

每當僅寫入時,計數器加1,每當僅讀出時,計數器減1:

 

 當寫使能拉高且未讀滿時,寫指標地址加1;當讀使能拉高且未讀空時,讀指標地址加1:

 

 

 

 當寫使能時,資料寫入RAM;當讀使能時,資料從RAM讀出:

 

 最後,對寫滿和讀空條件進行判斷:

 

 testbench:

`timescale 1ns / 1ns
module sync_fifo_tb();
    parameter                           DATA_WIDTH=8
; parameter DATA_DEPTH=8 ; reg clk ; reg rstn ; reg wr_en ; reg [DATA_WIDTH-1
:0] wr_data ; wire wr_full ; reg rd_en ; wire [DATA_WIDTH-1:0] rd_data ; wire rd_empty ; sync_fifo #( .DATA_WIDTH (DATA_WIDTH ), .DATA_DEPTH (DATA_DEPTH ) ) u_sync_fifo( .clk (clk ), .rstn (rstn ), .wr_en (wr_en ), .wr_data (wr_data ), .wr_full (wr_full ), .rd_en (rd_en ), .rd_data (rd_data ), .rd_empty (rd_empty ) ); initial clk=1; always#10 clk=!clk; initial begin rstn=0; wr_en=0; rd_en=0; //@(negedge clk)rstn=1; //@(negedge clk)wr_en=1; #21; rstn=1; #100; wr_en=1; wr_data=8'h53; #20; wr_data=8'h7a; #20; wr_data=8'hff; #20; wr_data=8'h69; #20; wr_en=0; #100; rd_en=1; #80; rd_en=0; #100; wr_en=1; wr_data=8'h11; #20; wr_data=8'h22; #20; wr_data=8'h33; #20; wr_data=8'h66; #20; wr_data=8'h99; #20; wr_en=0; rd_en=1; #100; rd_en=0; #100 $finish; end endmodule

模擬結果:

 

 寫入RAM時,0地址對應53,1地址對應7a,2地址對應ff,3地址對應69,讀出時53,7a,ff,69分別對應讀指標為0,1,2,3;當寫使能訊號拉高時,在下一個時鐘上升沿寫指標才加1,這是由於阻塞賦值,這也對應了上文所說的每一次FIFO寫動作都會將資料寫入當前寫指標對應的儲存器地址,然後寫指標加1,指向一個新的未寫的Memory空間。當計數器為0時,說明所有資料被讀出,讀空訊號拉高。一開始讀空訊號也是拉高的,直到開始寫入資料。最後可以看出,當寫入第九個資料後,buffer[0]變為8‘h99。在FIFO設計中,一定要注意不要往寫滿的FIFO中寫入,不要從讀空的FIFO中的讀出。