【原创】基于两种模式下的同步FIFO设计
1赞所谓FIFO就是先进先出的意思,通俗的说,就像数据从一个管道的一端进去而从管道的另一端输出。FIFO是一个没有地址端口的存储器,它依靠内部写指针(指定写数据的位置)和读指针(指定读数据的位置)来进行数据的存储或读取。
FIFO有同步FIFO和异步FIFO之分。它们的区别是同步FIFO数据的读写受同一时钟源的控制,而异步FIFO的读写则可以受不同时钟源控制。在这里,我将要介绍的是基于同步的FIFO设计。下面分别介绍基于移位寄存器模式和基于双端口RAM模式的同步FIFO设计。
1、基于移位寄存器的同步FIFO设计
基于移位寄存器的同步FIFO只需一个读指针,指示FIFO中第一个有效数据,如图1所示。
图1 基于移位寄存器的FIFO读写数据过程
这里设计一个数据位宽和FIFO深度都可设置的简单FIFO,其实现电路如下所示:
/***************************Copyright******************************* ** CrazyBird ** http://blog.chinaaet.com/crazybird ** **----------------------File Infomation----------------------------- ** FileName : syn_fifo.v ** Author : CrazyBird ** Data : 2015-11-14 ** Version : v1.0 ** Description : Synchronous FIFO design based on shift register ** *******************************************************************/ // synopsys translate_off `timescale 1 ns / 1 ps // synopsys translate_on module syn_fifo #( parameter DATA_WIDTH = 8, parameter FIFO_DEPTH = 8 ) ( input rst_n, input clk, input [DATA_WIDTH-1:0] din, input push, input pop, output [DATA_WIDTH-1:0] dout, output reg full, output reg empty ); //------------------------------------------------------------------ // Parameter definition localparam A_EMPTY = 0; localparam A_FULL = FIFO_DEPTH - 2; //------------------------------------------------------------------ // Variable definition reg [DATA_WIDTH-1:0] mem [0:FIFO_DEPTH-1]; integer read_cnt; //------------------------------------------------------------------ // Write data always @(posedge clk) begin : shift_reg integer i; if((push & ~full) == 1'b1) begin for(i = 0;i < FIFO_DEPTH-1;i = i+1) mem[i+1] <= mem[i]; mem[0] <= din; end end //------------------------------------------------------------------ // Read pointer always @(posedge clk) begin if(rst_n == 1'b0) read_cnt <= FIFO_DEPTH-1'b1; else if((push & ~pop & ~full) == 1'b1) begin if(read_cnt == FIFO_DEPTH-1'b1) read_cnt <= 0; else read_cnt <= read_cnt + 1'b1; end else if((~push & pop & ~empty) == 1'b1) begin if(read_cnt == A_EMPTY) read_cnt <= FIFO_DEPTH-1; else read_cnt <= read_cnt -1'b1; end end //------------------------------------------------------------------ // Empty indicator always @(posedge clk) begin if(rst_n == 1'b0) empty <= 1'b1; else if((~push & pop & (read_cnt==A_EMPTY)) == 1'b1) empty <= 1'b1; else if((push & ~pop) == 1'b1) empty <= 1'b0; end //------------------------------------------------------------------ // Full indicator always @(posedge clk) begin if(rst_n == 1'b0) full <= 1'b0; else if((push & ~pop & (read_cnt==A_FULL)) == 1'b1) full <= 1'b1; else if((~push & pop) == 1'b1) full <= 1'b0; end //------------------------------------------------------------------ // Data output assign dout = (FIFO_DEPTH==1) ? mem[0] : mem[read_cnt]; endmodule /**************************End File*********************************
FIFO写仿真波形如图2所示。
图2 FIFO写数据
FIFO读仿真波形如图3所示。
图3 FIFO读数据
此外,该设计还支持同时读写FIFO,但有两个限制。第一个限制是,当FIFO为空时,只支持写操作,不支持同时读写操作;第二个限制是,当为FIFO为满时,只支持读操作,不支持同时读写操作。
2、基于双端口RAM的同步FIFO设计
基于双端口RAM的同步FIFO需要读指针和写指针两个指针,分别指示读取数据和写数据的位置,如图4所示。
图4 基于双端口RAM的FIFO读写数据过程
这里设计一个数据位宽和FIFO深度都可设置的简单FIFO,其实现电路如下所示:
/***************************Copyright******************************* ** CrazyBird ** http://blog.chinaaet.com/crazybird ** **----------------------File Infomation----------------------------- ** FileName : syn_fifo.v ** Author : CrazyBird ** Data : 2015-11-14 ** Version : v1.0 ** Description : Synchronous FIFO design based on dual port RAM ** *******************************************************************/ // synopsys translate_off `timescale 1 ns / 1 ps // synopsys translate_on module syn_fifo #( parameter DATA_WIDTH = 8, parameter FIFO_DEPTH = 8 ) ( input rst_n, input clk, input [DATA_WIDTH-1:0] din, input push, input pop, output [DATA_WIDTH-1:0] dout, output full, output empty ); //------------------------------------------------------------------ // Variable definition reg [DATA_WIDTH-1:0] mem [0:FIFO_DEPTH-1]; integer read_cnt; integer write_cnt; integer count; //------------------------------------------------------------------ // Write data always @(posedge clk) begin if((push & ~full) == 1'b1) mem[write_cnt] <= din; end //------------------------------------------------------------------ // Read and write pointer,number of data in fifo always @(posedge clk) begin if(rst_n == 1'b0) begin read_cnt <= 0; write_cnt <= 0; count <= 0; end else begin case({push,pop}) 2'b10 : begin if(count < FIFO_DEPTH) begin count <= count + 1'b1; if(write_cnt < FIFO_DEPTH-1) write_cnt 0) begin count <= count - 1'b1; if(read_cnt < FIFO_DEPTH-1) read_cnt <= read_cnt + 1'b1; else read_cnt <= 0; end end 2'b11 : begin if(write_cnt < FIFO_DEPTH-1) write_cnt <= write_cnt + 1'b1; else write_cnt <= 0; if(read_cnt < FIFO_DEPTH-1) read_cnt <= read_cnt + 1'b1; else read_cnt <= 0; end default : ; endcase end end //------------------------------------------------------------------ // Data output assign full = (count == FIFO_DEPTH); assign empty = (count == 0); assign dout = mem[read_cnt]; endmodule /**************************End File*********************************
FIFO写仿真波形如图5所示。
图5 FIFO写数据
FIFO读仿真波形如图6所示。
图6 FIFO读数据
该设计也是有一个限制的,就是当为FIFO为满时,只支持读操作,不支持同时读写操作。
3、总结
由于在设计中我们规定了FIFO满后就不能再写数据,所以导致了基于移位寄存器的FIFO的第二个限制和基于双端口RAM的FIFO的限制。如果想去掉这个限制,节将写FIFO的条件由if((push & ~full) == 1'b1)改为if(push == 1'b1)即可。