同步FIFO的两种实现方式
基于移位寄存器的同步FIFO

`timescale 1ns/1ps
module sync_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
);
localparam A_EMPTY = 0;
localparam A_FULL = FIFO_DEPTH - 2;
reg [DATA_WIDTH-1:0] mem [FIFO_DEPTH-1:0];
integer read_cnt;
// write data
integer i;
always @(posedge clk)begin
if (push & ~full)begin
for(i = 0; i < FIFO_DEPTH; i = i + 1)begin
mem[i+1] <= mem[i];
mem[0] <= din;
end
end
end
// read pointer
// read pointer is initialized as FIFO_DEPTH-1'b1
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
read_cnt <= FIFO_DEPTH-1'b1;
else if(push & !pop & !full) begin
if(read_cnt == FIFO_DEPTH-1'b1)
read_cnt <= 0;
else
read_cnt <= read_cnt + 1'b1;
end
else if (!push & pop & !empty)begin
if(read_cnt == A_EMPTY)
read_cnt <= FIFO_DEPTH - 1'b1;
else
read_cnt <= read_cnt - 1'b1;
end
end
// empty indicating
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
empty <= 1'b1;
else if (~push & pop & ((read_cnt == A_EMPTY) == 1'b1))
empty <= 1'b1;
else if (!pop & push)
empty <= 1'b0;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
full <= 1'b0;
else if (push & ~pop & (read_cnt == A_FULL))
full <= 1'b1;
else if (pop & !push)
full <= 1'b0;
end
// data output
assign dout = (FIFO_DEPTH == 1) ? mem[0] : mem[read_cnt];
endmodule
`timescale 1ns/1ps
module tb;
reg clk, rst_n;
reg [7:0] din;
wire [7:0] dout;
reg push, pop;
initial begin
clk = 0;
#5 clk = 1;
forever #5 clk = ~clk;
end
initial begin
rst_n = 0;
#15 rst_n = 1;
end
initial begin
push = 0;
#29 push = 1;
#89 push = 0;
pop = 1;
#169
pop = 0;
$finish;
end
initial begin
forever #9 din = $random();
end
sync_fifo inst (
rst_n, clk, din, push, pop, dout, full, empty
);
endmodule
基于双口RAM的同步FIFO
`timescale 1ns/1ns
module dual_port_RAM
#(
parameter WIDTH = 8,
parameter DEPTH = 16
)
(
input wclk,
input wenc,
input [$clog2(DEPTH)-1:0] waddr,
input [WIDTH-1:0] wdata,
input rclk,
input renc,
input [$clog2(DEPTH)-1:0] raddr,
output reg [WIDTH-1:0] rdata
);
reg [WIDTH-1:0] mem [0:DEPTH-1];
always @(posedge wclk)begin
if(wenc)
mem[waddr] <= wdata;
end
always @(posedge rclk)begin
if(renc)
rdata <= mem[raddr];
end
endmodule
// -------------------------------------------------------
module sfifo
#(
parameter WIDTH = 8,
parameter DEPTH = 16
)
(
input clk,
input rst_n,
input winc,
input rinc,
input [WIDTH-1:0] wdata,
output reg wfull,
output reg rempty,
output wire [WIDTH-1:0] rdata
);
parameter ADDR_WIDTH = $clog2(DEPTH);
reg [ADDR_WIDTH:0] wr_ptr, rd_ptr;
wire wenc, renc;
//assign wfull = (wr_ptr - rd_ptr) == DEPTH;
//assign rempty = wr_ptr == rd_ptr;
assign wenc = winc & ~wfull;
assign renc = rinc & ~rempty;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
wfull <= 1'b0;
rempty <= 1'b0;
end
else begin
wfull = (wr_ptr - rd_ptr) == DEPTH;
rempty = wr_ptr == rd_ptr;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
wr_ptr <= 1'b0;
else if (wenc)
wr_ptr <= wr_ptr + 1'b1;
else
wr_ptr <= wr_ptr;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
rd_ptr <= 1'b0;
else if (renc)
rd_ptr <= rd_ptr + 1'b1;
else
rd_ptr <= rd_ptr;
end
dual_port_RAM inst
(
clk, wenc, wr_ptr[ADDR_WIDTH-1:0], wdata, clk, renc, rd_ptr[ADDR_WIDTH-1:0],
rdata
);
endmodule
异步FIFO双口RAM
`timescale 1ns/1ns
module dual_port_RAM
#(
parameter WIDTH = 8,
parameter DEPTH = 16
)
(
input wclk,
input wenc,
input [$clog2(DEPTH)-1:0] waddr,
input [WIDTH-1:0] wdata,
input rclk,
input renc,
input [$clog2(DEPTH)-1:0] raddr,
output reg [WIDTH-1:0] rdata
);
reg [WIDTH-1:0] mem [DEPTH-1:0];
always @(posedge wclk)begin
if(wenc)
mem[waddr] <= wdata;
end
always @(posedge rclk) begin
if(renc)
rdata <= mem[raddr];
end
endmodule
// --------------------------------------------
module asyn_fifo
#(
parameter WIDTH = 8,
parameter DEPTH = 16
)
(
input wclk,
input rclk,
input wrstn,
input rrstn,
input winc,
input rinc,
input [WIDTH-1:0] wdata,
output wire wfull,
output wire rempty,
output wire [WIDTH-1:0] rdata
);
parameter ADDR_WIDTH = $clog2(DEPTH);
reg [ADDR_WIDTH:0] wr_ptr, wr_grey0, wr_grey1, wr_grey2;
reg [ADDR_WIDTH:0] rd_ptr, rd_grey0, rd_grey1, rd_grey2;
wire [ADDR_WIDTH:0] wr_grey, rd_grey;
wire wenc, renc;
assign wr_grey = wr_ptr >> 1 ^ wr_ptr;
assign rd_grey = rd_ptr >> 1 ^ rd_ptr;
assign wfull = wr_grey0 == {~rd_grey2[ADDR_WIDTH:ADDR_WIDTH-1], rd_grey2[ADDR_WIDTH-2:0]};
assign rempty = rd_grey0 == wr_grey2;
assign wenc = winc & ~wfull;
assign renc = rinc & ~rempty;
always @(posedge wclk or negedge wrstn)begin
if(!wrstn)
wr_ptr <= 1'b0;
else if (wenc)
wr_ptr <= wr_ptr + 1'b1;
end
always @(posedge rclk or negedge rrstn)begin
if(!rrstn)
rd_ptr <= 1'b0;
else if (renc)
rd_ptr <= rd_ptr + 1'b1;
end
always @(posedge wclk or negedge wrstn)begin
if(!wrstn)
wr_grey0 <= 1'b0;
else
wr_grey0 <= wr_grey;
end
always @(posedge rclk or negedge rrstn)begin
if(!rrstn)
rd_grey0 <= 1'b0;
else
rd_grey0 <= rd_grey;
end
always @(posedge wclk or negedge wrstn)begin
if(!wrstn)
{rd_grey2, rd_grey1} <= 'b0;
else
{rd_grey2, rd_grey1} <= {rd_grey1, rd_grey0};
end
always @(posedge rclk or negedge rrstn)begin
if (!rrstn)
{wr_grey2, wr_grey1} <= 'b0;
else
{wr_grey2, wr_grey1} <= {wr_grey1, wr_grey0};
end
dual_port_RAM inst
(wclk, wenc, wr_ptr[ADDR_WIDTH-1:0], wdata,
rclk, renc, rd_ptr[ADDR_WIDTH-1:0], rdata);
endmodule