FIFO

匿名 (未验证) 提交于 2019-12-03 00:11:01

FIFO是一种先入先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常方便,但缺点是只能顺序的写入数据、读出数据,其内部地址是由内部读写指针自动加1完成,不能像普通存储器那样由地址线读取或者写入某个地址。

FIFO的分类根据FIFO工作的时钟域,分为同步FIFO和异步FIFO。同步FIFO是指读写时钟为同一时钟。在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟相互独立。

FIFO设计的难点在于怎么判断FIFO的空满状态。为了保证数据正确的写入和读出,而不发生溢出或读空的状态出现,必须保证FIFO在满的情况下,不能进行写操作。在空的状态下不能进行读操作。

同步FIFO的实现代码:

 1 module fifo(   //信号定义---读、写、data_in,data_out,clk,复位,空,满  2     input [7:0] datain,  3     input rd,//读  4     input wr,//写  5     input rst,  6     input clk,  7     output [7:0] dataout,  8     output full,  9     output empty, 10     ); 11      12     wire [7:0] dataout;//输出信号定义为wire类型 ,输入默认为wire 13     reg full_in,empty_in;  (空满寄存器) 14     reg [7:0] mem [15:0];//RAM的深度和宽度 15      16     reg [3:0] rp,wp; //读写指针的寄存 17      18     //空满输出 19     assign full = full_in; 20     assign empty = empty_in; 21      22     //read    always@(posedge clk) begin      if(rd && ~empty_in) dataout <= men[rp];      end
 23     //assign dataout = mem[rp]; 24      25     //write 26     always@(posedge clk) begin 27         if(wr && ~full_in)  mem[wp] <=datain; 28     end 29      30     // 读指针读完自增 31     always@(posedge clk or negedge rst) begin 32         if(!rst) rp<=0; 33         else begin 34             if(rd && ~empty_in) rp<=rp+1'b1; 35         end 36     //写指针自增 37     always@(posedge clk or negedge rst) begin 38         if (!rst) wp<=0; 39         else begin     40             if(wd && ~full_in) wp<=wp+1'b1; 41         end 42      43     //满状态生成 44     always@(posedge clk or negedge rst) begin 45         if(~rst) full_in<=0;  //复位 46         else begin 47             if((~rd && wr)&& ((wp=rp-1)||(rp==4'0&&wp==4'hf)))  //读指针在写指针之后,且下一个来临的是一个写信号,则写满 48                 full_in<=1'b1; 49         else if (full_in && rd) full_in <=1'b0;//当满状态时来了读信号,则满状态拉低。 50         end 51     //空状态生成 52     always@(posedge clk or negedge rst)begin 53         if(~rst) empty_in<=1'b0; 54         else begin 55             if((rd && ~wr)&&(rp = wr -1 || (rp==4'hf&&wp==4'h0))) 56                 empty_in<=0; 57             else if(empty_in && wr ) empty_in<=1'b0; 58         end 59         end 60 endmodule

异步FIFO的实现:

不同点在于增加了读写控制信号的跨时钟域的同步,此外判断空满也不同。

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<<ASIZE)-1]; wire [ASIZE-1:0] waddr, raddr; wire [ASIZE:0] rgraynext, rbinnext,wgraynext,wbinnext; wire rempty_val,wfull_val; //-----------------双口RAM存储器-------------------- assign rdata=mem[raddr]; always@(posedge wclk) if (winc && !wfull) mem[waddr] <= wdata; //-------------同步rptr 指针------------------------- always @(posedge wclk or negedge wrst_n) if (!wrst_n) {wq2_rptr,wq1_rptr} <= 0; else {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr}; //-------------同步wptr指针--------------------------- always @(posedge rclk or negedge rrst_n) if (!rrst_n) {rq2_wptr,rq1_wptr} <= 0; else {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr}; //-------------rempty产生与raddr产生------------------- always @(posedge rclk or negedge rrst_n) // GRAYSTYLE2 pointer begin if (!rrst_n) {rbin, rptr} <= 0; else {rbin, rptr} <= {rbinnext, rgraynext}; end // Memory read-address pointer (okay to use binary to address memory) assign raddr = rbin[ASIZE-1:0]; assign rbinnext = rbin + (rinc & ~rempty);//下一个地址 assign rgraynext = (rbinnext>>1) ^ rbinnext;//求格雷码 // FIFO empty when the next rptr == synchronized wptr or on reset assign rempty_val = (rgraynext == rq2_wptr); always @(posedge rclk or negedge rrst_n) begin if (!rrst_n) rempty <= 1'b1; else rempty <= rempty_val; end //---------------wfull产生与waddr产生------------------------------ always @(posedge wclk or negedge wrst_n) // GRAYSTYLE2 pointer if (!wrst_n) {wbin, wptr} <= 0; else {wbin, wptr} <= {wbinnext, wgraynext}; // Memory write-address pointer (okay to use binary to address memory) assign waddr = wbin[ASIZE-1:0]; assign wbinnext = wbin + (winc & ~wfull);//地址自增 assign wgraynext = (wbinnext>>1) ^ wbinnext; assign wfull_val = (wgraynext=={~wq2_rptr[ASIZE:ASIZE-1], wq2_rptr[ASIZE-2:0]}); //:ASIZE-1] always @(posedge wclk or negedge wrst_n) if (!wrst_n) wfull <= 1'b0; else wfull <= wfull_val; endmodule

二进制计数器存在的问题:

  异步FIFO读写指针需要在数学上的操作和比较才能产生准确的空满标志位,但由于读写指针属于不同的时钟域及读写指针以及读写时钟相位不定的原因,同一模块采集另一时钟域的指针时,此指针有可能正处在跳变过程中,那么采集到的值很可能是不期望的值。当然,不期望的错误结果也会随着产生。

  表现形式:最大的特点是在递增和递减过程中,每次只变化以为,这是它最大的优点。同时它也有自己的局限性,那就是循环计数深度必须是2的n次幂,否则就失去了每次只变化一位的特性。

  实现

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!