目录
一、前言
FIFO (First-In-First-Out) 是一种先进先出的数据交互方式,FIFO按工作时钟域的不同又可以分为:同步FIFO和异步FIFO。
同步FIFO的写时钟和读时钟为同一个时钟,FIFO内部所有逻辑都是同步逻辑,常常用于交互数据缓冲。异步FIFO的写时钟和读时钟为异步时钟,FIFO内部的写逻辑和读逻辑的交互需要异步处理,异步FIFO常用于跨时钟域处理。
更多介绍见FIFO存储器概念介绍_冬天里的棉袄博客-CSDN博客
二、原理
典型同步FIFO有三部分组成: (1) FIFO写控制逻辑; (2)FIFO读控制逻辑; (3)FIFO 存储实体(如Memory、Reg)。
FIFO写控制逻辑主要功能:产生FIFO写地址、写有效信号,同时产生FIFO写满、写错等状态信号;
FIFO读控制逻辑主要功能:产生FIFO读地址、读有效信号,同时产生FIFO读空、读错等状态信号。
如下图所示,FIFO读写过程的地址控制:
(1)当FIFO初始化(复位)时fifo_write_addr与fifo_read_addr同指到0x0,此时FIFO处于空状态;
(2)当FIFO进行写操作时,fifo_write_addr递增(增加到FIFO DEPTH时回绕),与fifo_read_addr错开,此时FIFO处于非空状态;
(3)当FIFO进行读操作时,fifo_read_addr递增;
FIFO空满状态产生:
为产生FIFO空满标志,引入FIFO Count计数器,FIFO Count寄数器用于指示FIFO内部存储数据个数;
(1)当只有写操作时,FIFO Count加1;只有读操作是,FIFO Count减1;其他情况下,FIFO Count保持;
(2)当FIFO Count为0时,说明FIFO为空,fifo_empty置位;
(3)当FIFO Count等于FIFO_DEPTH时,说明FIFO已满,fifo_full置位;
三、参考代码
19 module SYNC_FIFO_CTRL
20 (
21 clk ,
22 rst_n ,
23 fifo_wr_en ,
24 fifo_rd_en ,
25 fifo_wr_data ,
26 fifo_full ,
27 fifo_wr_err ,
28 fifo_empty ,
29 fifo_rd_err ,
30 fifo_data_cnt ,
31 fifo_rd_data
32 );
33
34 //PARA DECLARATION
35 parameter FIFO_DATA_WIDTH = 32 ;
36 parameter FIFO_ADDR_WIDTH = 8 ;
37
38 //INPUT DECLARATION
39 input clk ; //fifo clock
40 input rst_n ; //fifo clock reset (0: reset)
41 input fifo_wr_en ; //fifo write enable(1: enable)
42
43 input fifo_rd_en ; //fifo read enable(1: enable)
44 input [FIFO_DATA_WIDTH-1:0] fifo_wr_data ; //fifo write data
45
46 //OUTPUT DECLARATION
47 output fifo_full ; //fifo full status
48 output fifo_wr_err ; //fifo write error status
49 output fifo_empty ; //fifo empty status
50 output fifo_rd_err ; //fifo read error status
51 output [FIFO_ADDR_WIDTH :0] fifo_data_cnt; //fifo valid data cnt
52 output [FIFO_DATA_WIDTH-1:0] fifo_rd_data ; //fifo read data
53
54 //INTER DECLARATION
55 wire fifo_full ; //fifo full status
56 wire fifo_wr_err ; //fifo write error status
57 wire fifo_empty ; //fifo empty status
58 wire fifo_rd_err ; //fifo read error status
59 reg [FIFO_ADDR_WIDTH :0] fifo_data_cnt; //fifo valid data cnt
60 reg [FIFO_DATA_WIDTH-1:0] fifo_rd_data ; //fifo read data
61 reg [FIFO_ADDR_WIDTH-1:0] fifo_wr_addr ; //fifo write addr
62 reg [FIFO_ADDR_WIDTH-1:0] fifo_rd_addr ; //fifo write addr
63
64 //FIFO MEMORY INSTANCE
65 reg [FIFO_DATA_WIDTH-1:0] fifo_mem [{(FIFO_ADDR_WIDTH){1'b1}}:0] ;
66 integer i ;
67
68 //--========================MODULE SOURCE CODE==========================--
69
70 //--=========================================--
71 // SRAM INSTANCE :
72 // You Can use Reg Memory or Memory model here;
73 // FIFO Wdata & FIFO Rdata;
74 //--=========================================--
75 always @(posedge clk or negedge rst_n)
76 begin
77 if(rst_n == 1'b0)
78 begin
79 for(i=0;i<= {(FIFO_ADDR_WIDTH){1'b0}};i=i+1)
80 fifo_mem[i] <= {(FIFO_DATA_WIDTH){1'b0}} ;
81 end
82 else if (fifo_wr_en & (~ fifo_full))
83 fifo_mem[fifo_wr_addr] <= fifo_wr_data ;
84 end
85
86 always @(posedge clk or negedge rst_n)
87 begin
88 if(rst_n == 1'b0)
89 fifo_rd_data <= {(FIFO_DATA_WIDTH){1'b0}} ;
90 else if (fifo_rd_en & (~ fifo_empty))
91 fifo_rd_data <= fifo_mem[fifo_rd_addr] ;
92 end
93
94 //--=========================================--
95 // READ CONTROL :
96 // Read address increase when read enable AND
97 // Not empty;
98 //--=========================================--
99 always @(posedge clk or negedge rst_n)
100 begin
101 if(rst_n == 1'b0)
102 fifo_rd_addr <= {(FIFO_ADDR_WIDTH){1'b0}} ;
103 else if (fifo_rd_en & (~ fifo_empty))
104 fifo_rd_addr <= fifo_rd_addr + 1'b1 ;
105 end
106
107 //--=========================================--
108 // WRITE CONTROL :
109 // Write address increase when write enable AND
110 // Not full.
111 //--=========================================--
112 always @(posedge clk or negedge rst_n)
113 begin
114 if(rst_n == 1'b0)
115 fifo_wr_addr <= {(FIFO_ADDR_WIDTH){1'b0}} ;
116 else if (fifo_wr_en & (~ fifo_full))
117 fifo_wr_addr <= fifo_wr_addr + 1'b1 ;
118 end
119
120 //--=========================================--
121 // FIFO DATA CNT :
122 // Valid Write Only, increase data cnt;
123 // Valid Read Only, decrease data cnt;
124 //--=========================================--
125 always @(posedge clk or negedge rst_n)
126 begin
127 if(rst_n == 1'b0)
128 fifo_data_cnt <= {(FIFO_ADDR_WIDTH + 1){1'b0}} ;
129 else if (fifo_wr_en & (~ fifo_full) & (~(fifo_rd_en & (~fifo_empty)))) //Valid Write Only, increase data cnt;
130 fifo_data_cnt <= fifo_data_cnt + 1'b1 ;
131 else if (fifo_rd_en & (~ fifo_empty) & (~(fifo_wr_en & (~fifo_full)))) //Valid Read Only, decrease data cnt;
132 fifo_data_cnt <= fifo_data_cnt - 1'b1 ;
133 end
134
135 //--=========================================--
136 // FIFO Status :
137 // 1. fifo_empty when cnt ==0 ;
138 // 2. fifo full when cnt == MAX ;
139 //--=========================================--
140 assign fifo_empty = (fifo_data_cnt == 0 ) ;
141 assign fifo_rd_err = (fifo_data_cnt == 0 ) & fifo_rd_en ;
142
143 assign fifo_full = (fifo_data_cnt == ({(FIFO_ADDR_WIDTH){1'b1}} +1) ) ;
144 assign fifo_wr_err = (fifo_data_cnt == ({(FIFO_ADDR_WIDTH){1'b1}} +1) ) & fifo_wr_en ;
145
146 endmodule
三、功能完备一点的同步FIFO
下面这个FIFO具有寄存状room_avail,data_avail态判断FIFO内数据占用的状态
module synch_fifo #(parameter FIFO_PTR = 4,
FIFO_WIDTH = 32,
FIFO_DEPTH = 16)
(
clk,
rstn,
wren,
wrdata,
rden,
rddata,
full,
empty,
room_avail,
data_avail
);
//***********************************************************
input clk;
input rstn;
input wren;
input [FIFO_WIDTH-1:0] wrdata;
input rden;
input [FIFO_WIDTH-1:0] rddata;
output full;
output empty;
output [FIFO_PTR:0] room_avail;
output [FIFO_PTR:0] data_avail;
localparam FIFO_DEPTH_MINUS1 = FIFO_DEPTH-1;
//************************************************************
reg [FIFO_PTR-1:0] wr_ptr,wr_ptr_nxt;
reg [FIFO_PTR-1:0] rd_ptr,rd_ptr_nxt;
reg [FIFO_PTR:0] num_entries,num_entries_nxt;
reg full,empty;
wire full_next,empty_nxt;
reg [FIFO_PTR:0] room_avail;
wire [FIFO_PTR:0] room_avail_next;
wire [FIFO_PTR:0] data_avail;
//write-pointer control logic
//**********************************************************
always@(*)
begin
wr_ptr_next = wr_ptr;
if(wren)
begin
if(wr_ptr == FIFO_DEPTH_MINUS1)
wr_ptr_next = 'd0;
else
wr_ptr_nxt = wr_ptr + 1'b1;
end
end
//read-pointer control logic
//************************************************************
always@(*)
begin
rd_ptr_next = rd_ptr;
if(rden)
begin
if(rd_ptr == FIFO_DEPTH_MINUS1)
rd_ptr_next = 'd0;
else
rd_ptr_nxt = rd_ptr + 1'b1;
end
end
//Calculate number of occupied entries in the FIFO
//****************************************************************
always@(*)
begin
num_entries_nxt = num_entries;
if(wren && rden) //no change to num_entries
num_entries_nxt = num_entries;
else if(wren)
num_entries_nxt = num_entries + 1'b1;
else if(rden)
num_entries_nxt = num_entries - 1'b1;
end
assign full_nxt = (num_entries_nxt == FIFO_DEPTH);
assign empty_nxt = (num_entries_nxt == 'd0);
assign data_avail = num_entries;
assign room_avail_nxt = (FIFO_DEPTH - num_entries_nxt);
//********************************************************************
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
wr_ptr <= 'd0;
rd_ptr <= 'd0;
num_entries <= 'd0;
full <=1'b0;
empty <=1'b1;
room_avail <=FIFO_DEPTH;
end
else
begin
wr_ptr <= wr_ptr_nxt;
rd_ptr <= rd_ptr_nxt;
num_entries <= num_entries_nxt;
full <= full_nxt;
empty <= empty_nxt;
room_avail <= room_avail_nxt;
end
end
//SRAM memory instantiation
//***********************************************************************
sram u_srm #(.ADDR_WIDTH (FIFO_PTR),
.DATA_WIDTH (FIFO_WIDTH),
.MEM_DEPTH (FIFO_DEPTH))
(.wrclk (clk),
.rdclk (clk),
.wren (wren),
.rden (rden),
.wraddr (wr_ptr),
.rdaddr (rd_ptr),
.wrdata (wrdata),
.rddata (rddata)
);
endmodule
双端口RAM代码
//dual port RAM
module sram #(parameter ADDR_WIDTH = 3,
DATA_WIDTH = 8,
MEM_DEPTH = 8)
(
rddata,
wraddr,
rdaddr,
wrdata,
wren,
rden,
wrclk,
rdclk
);
output [DATA_WIDTH-1:0] rddata; //output data
input [DATA_WIDTH-1:0] wrdata; //input data
input [ADDR_WIDTH-1:0] wraddr; //write data address signal
input [ADDR_WIDTH-1:0] rdaddr; //output data address signal
input wren; //write data contral signal
input rden; //read data contral signal
input wrclk; //write data clock
input rdclk; //read data clock
reg [DATA_WIDTH-1:0] rddata;
reg [DATA_WIDTH-1:0]mem[MEM_DEPTH-1:0]; //8*8 bites register
always@(posedge wrclk)
begin
if(wren) begin
mem[wraddr] <= wrdata;
end
end
always@(posedge rdclk)
begin
if(rden) begin
rddata <= mem[rdaddr];
end
end
endmodule
参考链接: