FIFO緩存是介于兩個子系統之間的彈性存儲器,其概念圖如圖1所示。它有兩個控制信號,wr和rd,用于讀操作和寫操作。當wr被插入時,輸入的數據被寫入緩存,此時讀操作被忽視。FIFO緩存的head一般情況下總是有效的,因此可在任意時間被讀取。rd信號實際上就像“remove”信號;當其被插入的時候,FIFO緩存的第一個項(即head)被移除,下一個項變為可用項。
圖1 FIFO緩存的概念框圖
在許多應用中,FIFO緩存是一種臨界組件,其實現的優化相當復雜。在本節中,我們介紹一種簡單的、真實的基于循環序列設計的FIFO緩存。更有效的、基于指定器件實現的FIFO緩存可在Altera或Xilinx的相關手冊中找到。
基于循環隊列的實現
一種實現FIFO緩存的方法是給寄存器文件添加一個控制電路。寄存器文件通過兩個指針像循環隊列一樣來排列寄存器。寫指針(write poniter)指向隊列的頭(head);讀指針(read poniter)指向隊列的尾(tail)。每次讀操作或寫操作,指針都會前進一個位置。8-字循環隊列的操作如圖2所示。
圖2 基于循環隊列的FIFO緩存
FIFO緩存通常包括兩個標志信號,full和empty,相應地來指示FIFO滿(即不可寫)或FIFO空(即不可讀)。這兩種情況發生在讀指針和寫指針相等的時候,如圖2(a)、(f)和(i)所示的情況。控制器最難的設計任務是獲取一種分辨這兩種情形的機制。一種方案是使用觸發器來跟蹤empty和full標志。當系統被初始化時,觸發器被設置為1和0;然后在每一個時鐘周期根據wr和rd的值來修改。
代碼 FIFO緩存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
modulefifo #( parameterB=8, // number of bits in a word W=3 // number of address bits ) ( // global clock and aysn reset inputclk, inputrst_n, // fifo interface // fifo control signnal inputrd, inputwr, // fifo status signal outputempty, outputfull, // fifo data bus input[B-1:0] w_data, output[B-1:0] r_data ); // signal declaration reg[B-1:0] array_reg [2**W-1:0]; // register array reg[W-1:0] w_ptr_reg, w_ptr_next, w_ptr_succ; reg[W-1:0] r_ptr_reg, r_ptr_next, r_ptr_succ; regfull_reg, empty_reg, full_next, empty_next; wirewr_en; // body // register file write operation always@(posedgeclk) if(wr_en) array_reg[w_ptr_reg] <= w_data; // register file read operation assignr_data = array_reg[r_ptr_reg]; // write enabled only when FIFO is not full assignwr_en = wr & ~full_reg; // fifo control logic // register for read and write pointers always@(posedgeclk, negedgerst_n) if(!rst_n) begin w_ptr_reg <= 0; r_ptr_reg <= 0; full_reg <= 1'b0; empty_reg <= 1'b1; end else begin w_ptr_reg <= w_ptr_next; r_ptr_reg <= r_ptr_next; full_reg <= full_next; empty_reg <= empty_next; end // next-state logic for read and write pointers always@* begin // successive pointer values w_ptr_succ = w_ptr_reg + 1; r_ptr_succ = r_ptr_reg + 1; // default: keep old values w_ptr_next = w_ptr_reg; r_ptr_next = r_ptr_reg; full_next = full_reg; empty_next = empty_reg; case({wr, rd}) // 2'b00: no op 2'b01: // read if(~empty_reg) // not empty begin r_ptr_next = r_ptr_succ; full_next = 1'b0; if(r_ptr_succ==w_ptr_reg) empty_next = 1'b1; end 2'b10: // write if(~full_reg) // not full begin w_ptr_next = w_ptr_succ; empty_next = 1'b0; if(w_ptr_succ==r_ptr_reg) full_next = 1'b1; end 2'b11: // write and read begin w_ptr_next = w_ptr_succ; r_ptr_next = r_ptr_succ; end endcase end // output assignfull = full_reg; assignempty = empty_reg; endmodule |
代碼被分為寄存器文件和FIFO控制器兩部分。控制器由兩個指針和兩個標志觸發器組成,它們的次態邏輯會檢測wr和rd信號,以采取相應的動作。舉例說,在“10”條件下,即暗示只發生寫操作。先檢查標志觸發器,以確保緩存不為滿。如果滿足條件,我們將寫指針前進一位,并清除空標志。再多存儲一個字(偏移地址為1所對應的數據)可能使得FIFO緩存滿,即新的寫指針趕上了讀指針,我們使用w_ptr_succ==r_ptr_reg表達式來描述這一情況。
根據圖2,我寫了下面的testbench,其RTL仿真結果與圖2一致。
代碼 FIFO緩存的testbench
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
`timescale1ns/1ns modulefifo_tb; localparam T=20; // clock period // global clock and asyn reset regclk, rst_n; // fifo interface regrd, wr; wireempty, full; reg[7:0] w_data; wire[7:0] r_data; // fifo instantiation fifo #(.B(8), .W(3)) fifo_inst ( .clk(clk), .rst_n(rst_n), .rd(rd), .wr(wr), .empty(empty), .full(full), .w_data(w_data), .r_data(r_data) ); // clcok always begin clk = 1'b0; #(T/2); clk = 1'b1; #(T/2); end // reset initial begin rst_n = 1'b0; #(T/2) rst_n = 1'b1; end // stimulus body initial begin // initial input; empty rd=0; wr=0; w_data=8'h00; @(posedgerst_n); // wait to deassert rst_n @(negedgeclk); // wait for a clock // 1 write wr=1; w_data=8'h11; @(negedgeclk); // wait to assert wr wr=0; @(negedgeclk); // wait to deassert wr // 3 writes wr=1; repeat(3) begin w_data=w_data+8'h11; @(negedgeclk); end wr=0; @(negedgeclk); // 1 read rd=1; @(negedgeclk); // wait to assert rd rd=0; @(negedgeclk) // wait to deassert rd // 4 writes wr=1; repeat(4) begin w_data=w_data+8'h11; @(negedgeclk); end wr=0; @(negedgeclk); // 1 write; full wr=1; w_data=8'hAA; @(negedgeclk); wr=0; @(negedgeclk); // 2 reads rd=1; repeat(2) @(negedgeclk); rd=0; @(negedgeclk); // 5 reads rd=1; repeat(5) @(negedgeclk); rd=0; @(negedgeclk); // 1 read; empty rd=1; @(negedgeclk); rd=0; @(negedgeclk); $stop; end endmodule |
圖3 RTL級仿真波形
審核編輯:湯梓紅
-
寄存器
+關注
關注
31文章
5325瀏覽量
120052 -
fifo
+關注
關注
3文章
387瀏覽量
43561 -
Verilog
+關注
關注
28文章
1345瀏覽量
109996 -
緩存
+關注
關注
1文章
233瀏覽量
26649 -
RTL
+關注
關注
1文章
385瀏覽量
59710
原文標題:Verilog設計FIFO
文章出處:【微信號:Hack電子,微信公眾號:Hack電子】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論