FIFO緩存,Verilog實現(xiàn)機制
掃描二維碼
隨時隨地手機看文章
內容
FIFO緩存是介于兩個子系統(tǒng)之間的彈性存儲器,其概念圖如圖1所示。它有兩個控制信號,wr和rd,用于讀操作和寫操作。當wr被插入時,輸入的數(shù)據(jù)被寫入緩存,此時讀操作被忽視。FIFO緩存的head一般情況下總是有效的,因此可在任意時間被讀取。rd信號實際上就像“remove”信號;當其被插入的時候,F(xiàn)IFO緩存的第一個項(即head)被移除,下一個項變?yōu)榭捎庙棥?
圖1 FIFO緩存的概念框圖
在許多應用中,F(xiàn)IFO緩存是一種臨界組件,其實現(xiàn)的優(yōu)化相當復雜。在本節(jié)中,我們介紹一種簡單的、真實的基于循環(huán)序列設計的FIFO緩存。更有效的、基于指定器件實現(xiàn)的FIFO緩存可在Altera或Xilinx的相關手冊中找到。
基于循環(huán)隊列的實現(xiàn)
一種實現(xiàn)FIFO緩存的方法是給寄存器文件添加一個控制電路。寄存器文件通過兩個指針像循環(huán)隊列一樣來排列寄存器。寫指針(write poniter)指向隊列的頭(head);讀指針(read poniter)指向隊列的尾(tail)。每次讀操作或寫操作,指針都會前進一個位置。8-字循環(huán)隊列的操作如圖2所示。
圖2 基于循環(huán)隊列的FIFO緩存
FIFO緩存通常包括兩個標志信號,full和empty,相應地來指示FIFO滿(即不可寫)或FIFO空(即不可讀)。這兩種情況發(fā)生在讀指針和寫指針相等的時候,如圖2(a)、(f)和(i)所示的情況??刂破髯铍y的設計任務是獲取一種分辨這兩種情形的機制。一種方案是使用觸發(fā)器來跟蹤empty和full標志。當系統(tǒng)被初始化時,觸發(fā)器被設置為1和0;然后在每一個時鐘周期根據(jù)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控制器兩部分??刂破饔蓛蓚€指針和兩個標志觸發(fā)器組成,它們的次態(tài)邏輯會檢測wr和rd信號,以采取相應的動作。舉例說,在“10”條件下,即暗示只發(fā)生寫操作。先檢查標志觸發(fā)器,以確保緩存不為滿。如果滿足條件,我們將寫指針前進一位,并清除空標志。再多存儲一個字(偏移地址為1所對應的數(shù)據(jù))可能使得FIFO緩存滿,即新的寫指針趕上了讀指針,我們使用w_ptr_succ==r_ptr_reg表達式來描述這一情況。
根據(jù)圖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級仿真波形
參考
1 Pong P. Chu.FPGA Prototyping By Verilog Examples: Xilinx Spartan-3 Version.Wiley





