FIFO的英文全称为first in first out,顾名思义就是先进先出的意思。同步fifo表示读写时钟为同源,不存在跨异步处理。
1.1 原理
1.2 verilog代码
module sync_fifo #(
parameter DEPTH = 2,
WIDTH = 8,
PFCW = $clog2(DEPTH) + ((1 << $clog2(DEPTH)) == DEPTH)
)(
input clk,
input rst_n,
input push_valid,
input [WIDTH -1:0] push_data,
output push_ready,
output pop_valid,
output [WIDTH -1:0] pop_data,
input pop_ready
);
localparam DL = $clog2(DEPTH);
reg [WIDTH -1:0] mem[DEPTH -1:0];//FIFO data restore
reg [PFCW -1:0] free_cnt; //remain space
reg [PFCW -1:0] pop_cnt; //number of data
reg [DL -1:0] wrptr; //write pointer
reg [DL -1:0] rdptr; //read pointer
reg [WIDTH -1:0] wdata; //write data
reg [WIDTH -1:0] rdata; //read data
reg write; //write enable
reg read; //read enable
assign push_ready = ~push_full; //when fifo not full, write ready is high
assign write = push_valid & ~push_full; //write enable when fifo not full
assign wdata = push_data; //write data
assign pop_valid = ~pop_empty; //when fifo not empty, read valid is high
assign pop_data = rdata; //read data
assign read = pop_valid & ~pop_empty; //read enable when fifo not empty
//FIFO logic
//write side logic
always @(posedge clk or negedge rst_n) begin : write_data
if(~rst_n)
mem <= 'd0;
else if(write)
mem[wrptr] <= wdata; //write data to memory
end
always @(posedge clk or negedge rst_n) begin : write_pointer
if(~rst_n)
wrptr <= 'd0;
else if(write)
wrptr <= (wrptr == DEPTH -1) ? 'd0 : (wrptr +1'b1);
end
//read side logic
always @(posedge clk or negedge rst_n) begin : read_pointer
if(~rst_n)
rdptr <= 'd0;
else if(read)
rdptr <= (rdptr == DEPTH -1) ? 'd0 : (rdptr +1'b1);
end
assign rdata = mem[rdptr]; //from fifo to read data
//status
always @(posedge clk or negedge rst_n) begin : counter_management
if(~rst_n) begin
free_cnt <= DEPTH;
pop_cnt <= 'd0;
push_full <= 1'b0;
pop_empty <= 1'b1;
end
else if(read & ~write) begin
free_cnt <= free_cnt + 1'b1;
pop_cnt <= pop_cnt - 1'b1;
push_full <= 1'b0;
pop_empty <= (pop_cnt == 1)
end
else if(write & ~read) begin
free_cnt <= free_cnt - 1'b1;
pop_cnt <= pop_cnt + 1'b1;
push_full <= (free_cnt == 1);
pop_empty <= 1'b0;
end
end
endmodule