# 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 :

```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)
else
end

always_comb begin
if(!fifo_empty & rd_en)
else
end

always_ff @(posedge clk or negedge reset) begin
if(!reset)
else if (rd_en)
else
end

always_ff @(posedge clk or negedge reset) begin
if(!reset)
else if (wr_en)
else
end

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

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

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 beginunique 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;endcaseendalways_ff @(posedge clk or negedge reset) beginif(!reset)  fifo_count_ff <= 3'b0;else  fifo_count_ff <= fifo_count;endassign 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;endalways_ff @(posedge clk or negedge reset) beginif (!reset)  wr_rollover_ff <= 1'b0;else  wr_rollover_ff <= wr_rollover;endalways_comb begin  if((rdaddr == 3'b0) & (!wr_en & rd_en))    rd_rollover = ~rd_rollover_ff;  else    rd_rollover = rd_rollover_ff;endalways_ff @(posedge clk or negedge reset) beginif (!reset)  rd_rollover_ff <= 1'b0;else  rd_rollover_ff <= rd_rollover;endassign 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);`