Synchronous FIFO :

Fifo (first-in-first-out) are used to for serial transfer of information whenever there is a difference of Transfer rate. The Transfer rate may differ due to difference in number of ports, frequency or data-width between source and destination.

The FIFO width is chosen to compensate for the Transfer rate and is calculated as follows:

Fifo size = Source Freq. * ports * Data-with / Dest. Freq. * ports * Data-with

Ex: Source : Port = 1, Freq. = 100KHz, Data-Width = 20
Destination : Port = 2, Freq. = 50KHz, Data-Width = 10
FIFO Size : 1*100*20/ 1*50*10 = 4 Entries

If the FIFO size is a fractional number then we round-up the FIFO size to nearest largest whole number. For Ex 4.33 -> 5.

Here’s a SV reference for 8 Entry deep FIFO with Data-Width of 32 bits :

8-Entry FIFO
logic [3:0] wraddr, rdaddr;
logic [7:0] wren, rden;
logic [31:0] data_ff[7:0];
logic [31:0] data_in, data_out;
logic wr_en, rd_en;
logic fifo_empty, fifo_full;

always_comb begin
if(!fifo_full & wr_en)
 wraddr = wraddr + 1;
else
 wraddr = wraddr_ff;
end

always_comb begin
 if(!fifo_empty & rd_en)
   rdaddr = rdaddr + 1;
 else
   rdaddr = rdaddr_ff;
end

always_ff @(posedge clk or negedge reset) begin
 if(!reset)
   rdaddr_ff <= 0;
 else if (rd_en)
  rdaddr_ff <=  rdaddr;
 else
  rdaddr_ff <= rdaddr_ff;
end

always_ff @(posedge clk or negedge reset) begin
 if(!reset)
   wraddr_ff <= 0;
 else if (wr_en)
  wraddr_ff <=  wraddr;
 else
  wraddr_ff <= wraddr_ff;
end

assign fifo_full = (wraddr[2:0] == rdaddr[2:0]) & 
                   (wraddr[3] != rdaddr[3]);

assign fifo_empty = (wraddr[2:0] == rdaddr[2:0]) & 
                    (wraddr[3] == rdaddr[3]);

assign wren = (wr_en == 1'b1) ? (1 << wraddr) : 8'b0;
assign rden = (rd_en == 1'b1) ? (1 << rdaddr) : 8'b0;

genvar i;
generate 
for (i = 0; i < 8; i++) begin  
always_ff @(posedge clk or negedge reset) begin
  if(wren[i]) 
     data_ff[i]  <= data_in;
   else
      data_ff[i] <= data_ff[i];
  end
end
endgenerate

always_comb begin
 for (int j = 0; j < 8; j++) begin
  if(rden[j]) 
    data_out = data_ff[j];
  else
    data_out = 8'b0;  
end

If the Fifo Width is not binary multiples of 2 , detecting full and empty conditions is difficult using above method. Alternately, we can use below two implementations that are more scalable with Fifo Widths:

1st implementation can be followed with a use of Single Counter to track Full and Empty conditions :

logic [2:0] fifo_count, fifo_count_ff;

always_comb begin
unique casez ({rd_en, wr_en})
2'b00 : fifo_count = fifo_count_ff;
2'b01 : fifo_count = (fifo_count_ff == 3'b111) ? 3'b111
: (fifo_count_ff + 3'b001);
2'b10 : fifo_count = (fifo_count_ff == 3'b0) ? 3'b0
: (fifo_count_ff - 3'b001);
2'b11 : fifo_count = fifo_count_ff;
endcase
end

always_ff @(posedge clk or negedge reset) begin
if(!reset)
fifo_count_ff <= 3'b0;
else
fifo_count_ff <= fifo_count;
end

assign fifo_full = (fifo_count == 3'b111);
assign fifo_empty = (fifo_count == 3'b0);

2nd implementation is using read and write roll-over pointers on wraddr and rdaddr.

logic wr_rollover, wr_rollover_ff;
logic rd_rollover, rd_rollover_ff;

always_comb begin
if((wraddr == 3'b111) & (wr_en & !rd_en))
wr_rollover = ~wr_rollover_ff;
else
wr_rollover = wr_rollover_ff;
end

always_ff @(posedge clk or negedge reset) begin
if (!reset)
wr_rollover_ff <= 1'b0;
else
wr_rollover_ff <= wr_rollover;
end

always_comb begin
if((rdaddr == 3'b0) & (!wr_en & rd_en))
rd_rollover = ~rd_rollover_ff;
else
rd_rollover = rd_rollover_ff;
end

always_ff @(posedge clk or negedge reset) begin
if (!reset)
rd_rollover_ff <= 1'b0;
else
rd_rollover_ff <= rd_rollover;
end

assign fifo_full = (wraddr[2:0] == rdaddr[2:0]) &
(wr_rollover != rd_rollover);

assign fifo_empty = (wraddr[2:0] == rdaddr[2:0]) &
(wr_rollover == rd_rollover);

Published by

tachyonyear

Silicon Design Enthusiast.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s