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





