1. 同步FIFO原理
2. Verilog 设计
module sync_fifo
(
fifo_wr ,
fifo_rd ,
fifo_din ,
fifo_dout ,
fifo_full ,
fifo_empty ,
clk ,
rstn
);
parameter FIFO_WIDTH = 16,
FIFO_DEPTH = 8,
FIFO_ADDR_BIT = 3;
input wire fifo_wr;
input wire fifo_rd;
input wire [FIFO_WIDTH-1:0] fifo_din;
output reg [FIFO_WIDTH-1:0] fifo_dout ;
output wire fifo_full;
output wire fifo_empty;
input wire clk;
input wire rstn;
integer i;
reg [FIFO_WIDTH-1:0] mem [0:FIFO_DEPTH-1];
//---读写指针扩展一位---//
reg [FIFO_ADDR_BIT:0]rd_ptr;
reg [FIFO_ADDR_BIT:0]wr_ptr;
always@(posedge clk or negedge rstn)begin
if(~rstn)begin
wr_ptr <= 'b0;
end else if(fifo_wr && !fifo_full)begin
wr_ptr <= wr_ptr + 1'b1;
end
end
always@(posedge clk or negedge rstn)begin
if(~rstn)begin
rd_ptr <= 'b0;
end else if(fifo_rd && !fifo_empty)begin
rd_ptr <= rd_ptr + 1'b1;
end
end
//--- write in ---//
always@(posedge clk or negedge rstn)begin
if(~rstn)begin
for(i=0; i<FIFO_DEPTH; i=i+1)begin
mem[i] <= 'd0;
end
end else if (fifo_wr && !fifo_full)begin
mem[wr_ptr[FIFO_ADDR_BIT-1:0]] <= fifo_din;
end
end
assign fifo_full = (wr_ptr[FIFO_ADDR_BIT] != rd_ptr[FIFO_ADDR_BIT])
& (wr_ptr[FIFO_ADDR_BIT-1:0] == rd_ptr[FIFO_ADDR_BIT-1:0]);
//--- read out ---//
always@(posedge clk or negedge rstn)begin
if(~rstn)begin
fifo_dout <= 'd0;
end
else if(fifo_rd && !fifo_empty)begin
fifo_dout = mem[rd_ptr[FIFO_ADDR_BIT-1:0]];
end
end
assign fifo_empty = (wr_ptr == rd_ptr)? 1'b1 : 1'b0;
endmodule
3. 测试用例(testbench)
`timescale 1ns/1ns
module tb();
parameter FIFO_WIDTH = 16,
FIFO_DEPTH = 8,
FIFO_ADDR_BIT = 3;
reg clk,rstn,fifo_wr,fifo_rd;
reg [FIFO_WIDTH-1:0] fifo_din;
wire fifo_empty,fifo_full;
wire [FIFO_WIDTH-1:0] fifo_dout;
always begin
#10 clk = ~clk;
end
initial begin
rstn = 0;
clk = 0;
repeat(5) @(posedge clk);
rstn = 1;
end
initial begin
fifo_wr = 0;
repeat(3) @(posedge clk);
fifo_wr = 1;
end
initial begin
fifo_rd = 0;
repeat(100) @(posedge clk);
fifo_rd = 1;
fifo_wr = 0;
end
initial begin
fifo_din = 16'h0;
#20 fifo_din = 16'h1;
#20 fifo_din = 16'h2;
#20 fifo_din = 16'h3;
#20 fifo_din = 16'h4;
#20 fifo_din = 16'h5;
#20 fifo_din = 16'h6;
#20 fifo_din = 16'h7;
#20 fifo_din = 16'h8;
#20 fifo_din = 16'h9;
#20 fifo_din = 16'ha;
#20 fifo_din = 16'hb;
#20 fifo_din = 16'hc;
#20 fifo_din = 16'hd;
#20 fifo_din = 16'he;
#20 fifo_din = 16'hf;
repeat(200) @(posedge clk);
$finish();
end
sync_fifo sync_fifo_inst
(
.fifo_wr (fifo_wr ),
.fifo_rd (fifo_rd ),
.fifo_din (fifo_din ),
.fifo_dout (fifo_dout ),
.fifo_full (fifo_full ),
.fifo_empty (fifo_empty),
.clk (clk ),
.rstn (rstn )
);
endmodule