FIFO 很重要,之前參加的各類電子公司的邏輯設(shè)計(jì)的筆試幾乎都會(huì)考到。
FIFO是英文First In First Out 的縮寫(xiě),是一種先進(jìn)先出的數(shù)據(jù)緩存器,他與普通存儲(chǔ)器的區(qū)別是沒(méi)有外部讀寫(xiě)地址線,這樣使用起來(lái)非常簡(jiǎn)單,但缺點(diǎn)就是只能順序?qū)懭霐?shù)據(jù),順序的讀出數(shù)據(jù), 其數(shù)據(jù)地址由內(nèi)部讀寫(xiě)指針自動(dòng)加1完成,不能像普通存儲(chǔ)器那樣可以由地址線決定讀取或?qū)懭肽硞€(gè)指定的地址。
?FIFO一般用于不同時(shí)鐘域之間的數(shù)據(jù)傳輸,比如FIFO的一端是AD數(shù)據(jù)采集, 另一端是計(jì)算機(jī)的PCI總線,假設(shè)其AD采集的速率為16位 100K SPS,那么每秒的數(shù)據(jù)量為100K×16bit=1.6Mbps,而PCI總線的速度為33MHz,總線寬度32bit,其最大傳輸速率為 1056Mbps,在兩個(gè)不同的時(shí)鐘域間就可以采用FIFO來(lái)作為數(shù)據(jù)緩沖。另外對(duì)于不同寬度的數(shù)據(jù)接口也可以用FIFO,例如單片機(jī)位8位數(shù)據(jù)輸出,而 DSP可能是16位數(shù)據(jù)輸入,在單片機(jī)與DSP連接時(shí)就可以使用FIFO來(lái)達(dá)到數(shù)據(jù)匹配的目的。
?
FIFO的分類根均FIFO工作的時(shí)鐘域,可以將FIFO分為同步FIFO和異步FIFO。同步FIFO是指讀時(shí)鐘和寫(xiě)時(shí)鐘為同一個(gè)時(shí)鐘。在時(shí)鐘沿來(lái)臨時(shí)同時(shí)發(fā)生讀寫(xiě)操作。異步FIFO是指讀寫(xiě)時(shí)鐘不一致,讀寫(xiě)時(shí)鐘是互相獨(dú)立的。
?
FIFO設(shè)計(jì)的難點(diǎn) FIFO設(shè)計(jì)的難點(diǎn)在于怎樣判斷FIFO的空/滿狀態(tài)。為了保證數(shù)據(jù)正確的寫(xiě)入或讀出,而不發(fā)生益處或讀空的狀態(tài)出現(xiàn),必須保證FIFO在滿的情況下,不 能進(jìn)行寫(xiě)操作。在空的狀態(tài)下不能進(jìn)行讀操作。怎樣判斷FIFO的滿/空就成了FIFO設(shè)計(jì)的核心問(wèn)題。
.........................................................................................................................................
同步FIFO的Verilog代碼 之一
在modlesim中驗(yàn)證過(guò)。
/******************************************************A fifo controller verilog description.******************************************************/module fifo(datain, rd, wr, rst, clk, dataout, full, empty);input [7:0] datain;input rd, wr, rst, clk;output [7:0] dataout;output full, empty;wire [7:0] dataout;reg full_in, empty_in;reg [7:0] mem [15:0];reg [3:0] rp, wp;assign full = full_in;assign empty = empty_in;// memory read outassign dataout = mem[rp];// memory write inalways@(posedge clk) begin??? if(wr && ~full_in) mem[wp]<=datain;end// memory write pointer incrementalways@(posedge clk or negedge rst) begin??? if(!rst) wp<=0;??? else begin????? if(wr && ~full_in) wp<= wp+1'b1;??? endend// memory read pointer incrementalways@(posedge clk or negedge rst)begin??? if(!rst) rp <= 0;??? else begin????? if(rd && ~empty_in) rp <= rp + 1'b1;??? endend// Full signal generatealways@(posedge clk or negedge rst) begin??? if(!rst) full_in <= 1'b0;??? else begin????? if( (~rd && wr)&&((wp==rp-1)||(rp==4'h0&&wp==4'hf)))????????? full_in <= 1'b1;????? else if(full_in && rd) full_in <= 1'b0;??? endend// Empty signal generatealways@(posedge clk or negedge rst) begin??? if(!rst) empty_in <= 1'b1;??? else begin????? if((rd&&~wr)&&(rp==wp-1 || (rp==4'hf&&wp==4'h0)))??????? empty_in<=1'b1;????? else if(empty_in && wr) empty_in<=1'b0;??? endendendmodule
...........................................................................................................................
同步FIFO的Verilog代碼 之二
這一種設(shè)計(jì)的FIFO,是基于觸發(fā)器的。寬度,深度的擴(kuò)展更加方便,結(jié)構(gòu)化跟強(qiáng)。以下代碼在modelsim中驗(yàn)證過(guò)。
module fifo_cell (sys_clk, sys_rst_n, read_fifo, write_fifo, fifo_input_data,??????????????????????? next_cell_data, next_cell_full, last_cell_full, cell_data_out, cell_full);??????????????????????? parameter WIDTH =8;??????????????????????? parameter D = 2;??????????????????????? input sys_clk;??????????????????????? input sys_rst_n;??????????????????????? input read_fifo, write_fifo;??????????????????????? input [WIDTH-1:0] fifo_input_data;??????????????????????? input [WIDTH-1:0] next_cell_data;??????????????????????? input next_cell_full, last_cell_full;??????????????????????? output [WIDTH-1:0] cell_data_out;??????????????????????? output cell_full;??????????????????????? reg [WIDTH-1:0] cell_data_reg_array;??????????????????????? reg [WIDTH-1:0] cell_data_ld;??????????????????????? reg cell_data_ld_en;??????????????????????? reg cell_full;??????????????????????? reg cell_full_next;??????????????????????? assign cell_data_out=cell_data_reg_array;??????????????????????? always @(posedge sys_clk or negedge sys_rst_n)?????????????????????????? if (!sys_rst_n)????????????????????????????? cell_full <= #D 0;?????????????????????????? else if (read_fifo || write_fifo)????????????????????????????? cell_full <= #D cell_full_next;??????????????????????? always @(write_fifo or read_fifo or next_cell_full or last_cell_full or cell_full)?????????????????????????? casex ({read_fifo, write_fifo})?????????????????????????????? 2'b00: cell_full_next = cell_full;?????????????????????????????? 2'b01: cell_full_next = next_cell_full;?????????????????????????????? 2'b10: cell_full_next = last_cell_full;?????????????????????????????? 2'b11: cell_full_next = cell_full;?????????????????????????? endcase???????????????????????? always @(posedge sys_clk or negedge sys_rst_n)????????????????????????????? if (!sys_rst_n)???????????????????????????????? cell_data_reg_array [WIDTH-1:0] <= #D 0;????????????????????????????? else if (cell_data_ld_en)???????????????????????????????? cell_data_reg_array [WIDTH-1:0] <= #D cell_data_ld [WIDTH-1:0];???????????????????????? always @(write_fifo or read_fifo or cell_full or last_cell_full)???????????????????????????????? casex ({write_fifo,read_fifo,cell_full,last_cell_full})????????????????????????????????? 4'bx1_xx: cell_data_ld_en = 1'b1;????????????????????????????????? 4'b10_01: cell_data_ld_en = 1'b1;????????????????????????????????? default: cell_data_ld_en =1'b0;????????????????????????????? endcase???????????????????????? always @(write_fifo or read_fifo or next_cell_full or cell_full or last_cell_full or fifo_input_data or next_cell_data)????????????????????????????? casex ({write_fifo, read_fifo, next_cell_full, cell_full, last_cell_full})???????????????????????????????? 5'b10_x01: cell_data_ld[WIDTH-1:0] = fifo_input_data[WIDTH-1:0];???????????????????????????????? 5'b11_01x: cell_data_ld[WIDTH-1:0] = fifo_input_data[WIDTH-1:0];???????????????????????????????? default: cell_data_ld[WIDTH-1:0] = next_cell_data[WIDTH-1:0];????????????????????????????? endcaseendmodule
?
module fifo_4cell(sys_clk, sys_rst_n, fifo_input_data, write_fifo, fifo_out_data,????????????????? read_fifo, full_cell0, full_cell1, full_cell2, full_cell3);????????????????? parameter WIDTH = 8;????????????????? parameter D = 2;????????????????? input sys_clk;????????????????? input sys_rst_n;????????????????? input [WIDTH-1:0] fifo_input_data;????????????????? output [WIDTH-1:0] fifo_out_data;????????????????? input read_fifo, write_fifo;????????????????? output full_cell0, full_cell1, full_cell2, full_cell3;????????????????? wire [WIDTH-1:0] dara_out_cell0, data_out_cell1, data_out_cell2,?????????????????????????????????? data_out_cell3, data_out_cell4;????????????????? wire full_cell4;????????????????? fifo_cell #(WIDTH,D) cell0????????????????? ( .sys_clk (sys_clk),??????????????????? .sys_rst_n (sys_rst_n),??????????????????? .fifo_input_data (fifo_input_data[WIDTH-1:0]),??????????????????? .write_fifo (write_fifo),??????????????????? .next_cell_data (data_out_cell1[WIDTH-1:0]),??????????????????? .next_cell_full (full_cell1),??????????????????? .last_cell_full (1'b1),??????????????????? .cell_data_out (fifo_out_data [WIDTH-1:0]),??????????????????? .read_fifo (read_fifo),??????????????????? .cell_full (full_cell0)?????????????????? );
????????????????? fifo_cell #(WIDTH,D) cell1????????????????? ( .sys_clk (sys_clk),??????????????????? .sys_rst_n (sys_rst_n),??????????????????? .fifo_input_data (fifo_input_data[WIDTH-1:0]),??????????????????? .write_fifo (write_fifo),??????????????????? .next_cell_data (data_out_cell2[WIDTH-1:0]),??????????????????? .next_cell_full (full_cell2),??????????????????? .last_cell_full (full_cell0),??????????????????? .cell_data_out (data_out_cell1[WIDTH-1:0]),??????????????????? .read_fifo (read_fifo),??????????????????? .cell_full (full_cell1)?????????????????? );??????????????????????????????????? fifo_cell #(WIDTH,D) cell2????????????????? ( .sys_clk (sys_clk),??????????????????? .sys_rst_n (sys_rst_n),??????????????????? .fifo_input_data (fifo_input_data[WIDTH-1:0]),??????????????????? .write_fifo (write_fifo),??????????????????? .next_cell_data (data_out_cell3[WIDTH-1:0]),??????????????????? .next_cell_full (full_cell3),??????????????????? .last_cell_full (full_cell1),??????????????????? .cell_data_out (data_out_cell2[WIDTH-1:0]),??????????????????? .read_fifo (read_fifo),??????????????????? .cell_full (full_cell2)?????????????????? );??????????????????
????????????????? fifo_cell #(WIDTH,D) cell3????????????????? ( .sys_clk (sys_clk),??????????????????? .sys_rst_n (sys_rst_n),??????????????????? .fifo_input_data (fifo_input_data[WIDTH-1:0]),??????????????????? .write_fifo (write_fifo),??????????????????? .next_cell_data (data_out_cell4[WIDTH-1:0]),??????????????????? .next_cell_full (full_cell4),??????????????????? .last_cell_full (full_cell2),??????????????????? .cell_data_out (data_out_cell3[WIDTH-1:0]),??????????????????? .read_fifo (read_fifo),??????????????????? .cell_full (full_cell3)?????????????????? );??????????????????????? assign data_out_cell4[WIDTH-1:0] = {WIDTH{1'B0}};?????????????????? assign full_cell4 = 1'b0;endmodule??????????????????????????????
..........................................................................................................................
異步FIFO的Verilog代碼 之一
這個(gè)是基于RAM的異步FIFO代碼,個(gè)人認(rèn)為代碼結(jié)構(gòu)簡(jiǎn)單易懂,非常適合于考試中填寫(xiě)。記得10月份參加威盛的筆試的時(shí)候,就考過(guò)異步FIFO的實(shí)現(xiàn)。想當(dāng)初要是早點(diǎn)復(fù)習(xí),可能就可以通過(guò)威盛的筆試了。
與之前的用RAM實(shí)現(xiàn)的同步FIFO的程序相比,異步更為復(fù)雜。增加了讀寫(xiě)控制信號(hào)的跨時(shí)鐘域的同步。此外,判空與判滿的也稍有不同。
module fifo1(rdata, wfull, rempty, wdata, winc, wclk, wrst_n,rinc, rclk, rrst_n);parameter DSIZE = 8; parameter ASIZE = 4;output [DSIZE-1:0] rdata;output wfull;output rempty;input [DSIZE-1:0] wdata;input winc, wclk, wrst_n;input rinc, rclk, rrst_n;reg wfull,rempty;reg [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr, wq1_rptr,rq1_wptr;reg [ASIZE:0] rbin, wbin;reg [DSIZE-1:0] mem[0:(1<
..........................................................................................................................
異步FIFO的Verilog代碼 之二
與前一段異步FIFO代碼的主要區(qū)別在于,空/滿狀態(tài)標(biāo)志的不同算法。
第一個(gè)算法:Clifford E. Cummings的文章中提到的STYLE #1,構(gòu)造一個(gè)指針寬度為N+1,深度為2^N字節(jié)的FIFO(為便方比較將格雷碼指針轉(zhuǎn)換為二進(jìn)制指針)。當(dāng)指針的二進(jìn)制碼中最高位不一致而其它N位都 相等時(shí),F(xiàn)IFO為滿(在Clifford E. Cummings的文章中以格雷碼表示是前兩位均不相同,而后兩位LSB相同為滿,這與換成二進(jìn)制表示的MSB不同其他相同為滿是一樣的)。當(dāng)指針完全相 等時(shí),F(xiàn)IFO為空。
這種方法思路非常明了,為了比較不同時(shí)鐘產(chǎn)生的指針,需要把不同時(shí)鐘域的信號(hào)同步到本時(shí)鐘域中來(lái),而使用Gray碼的目的就是使這個(gè)異步同步化的過(guò) 程發(fā)生亞穩(wěn)態(tài)的機(jī)率最小,而為什么要構(gòu)造一個(gè)N+1的指針,Clifford E. Cummings也闡述的很明白,有興趣的讀者可以看下作者原文是怎么論述的,Clifford E. Cummings的這篇文章有Rev1.1 \ Rev1.2兩個(gè)版本,兩者在比較Gray碼指針時(shí)的方法略有不同,個(gè)Rev1.2版更為精簡(jiǎn)。
第二種算法:Clifford E. Cummings的文章中提到的STYLE #2。它將FIFO地址分成了4部分,每部分分別用高兩位的MSB 00 、01、 11、 10決定FIFO是否為going full 或going empty (即將滿或空)。如果寫(xiě)指針的高兩位MSB小于讀指針的高兩位MSB則FIFO為“幾乎滿”,若寫(xiě)指針的高兩位MSB大于讀指針的高兩位MSB則FIFO 為“幾乎空”。
它是利用將地址空間分成4個(gè)象限(也就是四個(gè)等大小的區(qū)域),然后觀察兩個(gè)指針的相對(duì)位置,如果寫(xiě)指針落后讀指針一個(gè)象限(25%的距離,呵呵), 則證明很可能要寫(xiě)滿,反之則很可能要讀空,這個(gè)時(shí)候分別設(shè)置兩個(gè)標(biāo)志位dirset和dirrst,然后在地址完全相等的情況下,如果dirset有效就 是寫(xiě)滿,如果dirrst有效就是讀空。
這種方法對(duì)深度為2^N字節(jié)的FIFO只需N位的指針即可,處理的速度也較第一種方法快。??
這段是說(shuō)明的原話,算法一,還好理解。算法二,似乎沒(méi)有說(shuō)清楚,不太明白。有興趣的可以查查論文,詳細(xì)研究下。
總之,第二種寫(xiě)法是推薦的寫(xiě)法。因?yàn)楫惒降亩鄷r(shí)鐘設(shè)計(jì)應(yīng)按以下幾個(gè)原則進(jìn)行設(shè)計(jì):1,盡可能的將多時(shí)鐘的邏輯電路(非同步器)分割為多個(gè)單時(shí)鐘的模塊,這樣有利于靜態(tài)時(shí)序分析工具來(lái)進(jìn)行時(shí)序驗(yàn)證。2,同步器的實(shí)現(xiàn)應(yīng)使得所有輸入來(lái)自同一個(gè)時(shí)鐘域,而使用另一個(gè)時(shí)鐘域的異步時(shí)鐘信號(hào)采樣數(shù)據(jù)。3,面向時(shí)鐘信號(hào)的命名方式可以幫助我們確定那些在不同異步時(shí)鐘域間需要處理的信號(hào)。4,當(dāng)存在多個(gè)跨時(shí)鐘域的控制信號(hào)時(shí),我們必須特別注意這些信號(hào),保證這些控制信號(hào)到達(dá)新的時(shí)鐘域仍然能夠保持正確的順序。
module fifo2 (rdata, wfull, rempty, wdata,winc, wclk, wrst_n, rinc, rclk, rrst_n);parameter DSIZE = 8;parameter ASIZE = 4;output [DSIZE-1:0] rdata;output wfull;output rempty;input [DSIZE-1:0] wdata;input winc, wclk, wrst_n;input rinc, rclk, rrst_n;wire [ASIZE-1:0] wptr, rptr;wire [ASIZE-1:0] waddr, raddr;async_cmp #(ASIZE) async_cmp(.aempty_n(aempty_n),.afull_n(afull_n),.wptr(wptr), .rptr(rptr),.wrst_n(wrst_n));fifomem2 #(DSIZE, ASIZE) fifomem2(.rdata(rdata),.wdata(wdata),.waddr(wptr),.raddr(rptr),.wclken(winc),.wclk(wclk));rptr_empty2 #(ASIZE) rptr_empty2(.rempty(rempty),.rptr(rptr),.aempty_n(aempty_n),.rinc(rinc),.rclk(rclk),.rrst_n(rrst_n));wptr_full2 #(ASIZE) wptr_full2(.wfull(wfull),.wptr(wptr),.afull_n(afull_n),.winc(winc),.wclk(wclk),.wrst_n(wrst_n));endmodulemodule fifomem2 (rdata, wdata, waddr, raddr, wclken, wclk);parameter DATASIZE = 8; // Memory data word widthparameter ADDRSIZE = 4; // Number of memory address bitsparameter DEPTH = 1<
.............................................................
評(píng)論
查看更多