Sync FIFO
below is an implementation for sync fifo which:
utilize two pointers for recording write/read position
implemente a counter to record used space
follow handshake protocol. req_rdy LOW -> full, ack_vld LOW -> empty
support user defined payload
non-reset mem
//////////////////////////////////////////////////////////////////////////////////
// Company: URBADASS.LTD
// Engineer: zick
//
// Create Date: 02/26/2023 09:01:54 PM
// Design Name: sync fifo handshake
// Module Name: sync_fifo
// Project Name: sync fifo
// Description:
// a handshake based sync fifo for serialized data
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sync_fifo #(
parameter int unsigned DEPTH = 8 ,
parameter type PLD_TYPE = logic[32-1:0] ,
localparam int unsigned AWIDTH = $clog2(DEPTH)
)(
input logic clk ,
input logic rst_n ,
// Req
input logic req_vld,
output logic req_rdy,
input PLD_TYPE req_pld,
// ACK
output logic ack_vld,
input logic ack_rdy,
output PLD_TYPE ack_pld
);
//=================================================================
// Internal Signal
//=================================================================
PLD_TYPE pld_mem [DEPTH-1:0];
logic [AWIDTH-1 :0] wr_ptr ;
logic [AWIDTH-1 :0] rd_ptr ;
logic rd_en ;
logic wr_en ;
logic [AWIDTH :0] fifo_cnt ;
logic fifo_full ;
logic fifo_empty ;
//=================================================================
// WR/RD enable
//=================================================================
assign wr_en = req_vld && req_rdy;
assign rd_en = ack_vld && ack_rdy;
//=================================================================
// depth counter
//=================================================================
always_ff @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
fifo_cnt <= {AWIDTH+1{1'b0}};
end
else begin
case ({rd_en, wr_en})
{1'b1, 1'b0}: fifo_cnt <= (AWIDTH+1)'(fifo_cnt - 1'b1); // read, old version vcs/xrun does not support type(fifo_cnt)'
{1'b0, 1'b1}: fifo_cnt <= (AWIDTH+1)'(fifo_cnt + 1'b1); // write
default : fifo_cnt <= fifo_cnt; // no operation or read, write simultaneously
endcase
end
end
//=================================================================
// Empty & Full
//=================================================================
assign fifo_empty = ~|fifo_cnt;
assign fifo_full = fifo_cnt == DEPTH;
//=================================================================
// Handshake
//=================================================================
assign ack_vld = ~fifo_empty;
assign req_rdy = ~fifo_full;
//=================================================================
// WR/RD control
//=================================================================
always_ff @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
wr_ptr <= {AWIDTH{1'b0}};
end
else if (wr_en) begin
if (wr_ptr < DEPTH-1)
wr_ptr <= AWIDTH'(wr_ptr + 1'b1);
else
wr_ptr <= {AWIDTH{1'b0}};
end
end
always_ff @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
rd_ptr <= {AWIDTH{1'b0}};
end
else if (rd_en) begin
if (rd_ptr < DEPTH-1)
rd_ptr <= AWIDTH'(rd_ptr + 1'b1);
else
rd_ptr <= {AWIDTH{1'b0}};
end
end
//=================================================================
// Mem access
//=================================================================
always_ff @(posedge clk) begin
if (wr_en) pld_mem[wr_ptr] <= req_pld;
end
assign ack_pld = pld_mem[rd_ptr];
endmodule