Synchronous FIFO design code review
As a personal project, I have designed a synchronous FIFO in Verilog HDL. But while testing with a testbench, I observed that the FIFO values are flushed out after one clock cycle when read-enable is triggered but not exactly when the read-enable is triggered(i.e rd_en=1). I request for some help in this case like why it is happening and how to fix it. I have pasted my console output and the waveforms output of dut signals
Signals of FIFO
wr_data --> writes data into FIFO
wr_en --> write enable, required to write data into FIFO
rd_data --> reads data from the FIFO
rd_en --> read enable, required to read data from the FIFO
full --> tells the status of FIFO is full or not
empty --> tells the status of FIFO is empty or not
wr_ptr --> write pointer
rd_ptr --> read pointer
clk --> clock
rst --> reset
sync_fifo -> this is the actual FIFO memory
Verilog Design Code:
`// Code your design here
module sync_fifo_design(wr_data,wr_en,rd_data,rd_en,full,empty,clk,rst);
//Input and Output declarations
parameter data_width = 8;
parameter depth = 256;
input [data_width-1:0]wr_data;
input wr_en,rd_en,clk,rst;
output reg [data_width-1:0]rd_data;
output reg full,empty;
//here address width i.e for pointers is logarithmically related to depth of fifo
reg [$clog2(depth)-1:0]wr_ptr,rd_ptr;
reg [data_width-1:0]sync_fifo[0:depth-1];
initial begin
wr_ptr=0;
rd_ptr=0;
end
//full and empty conditions
always@(*) begin
if(rd_ptr==wr_ptr+1)
full<=1'b1;
else
full<=1'b0;
if(rd_ptr==wr_ptr)
empty<=1'b1;
else
empty<=1'b0;
end
//reset
always@(posedge clk) begin
if(rst) begin
wr_ptr<=0;
rd_ptr<=0;
rd_data<=0;
end
end
//Writing data into fifo
always@(posedge clk) begin
if(wr_en && !full) begin
sync_fifo[wr_ptr]<=wr_data;
wr_ptr<=wr_ptr+1;
end
end
//read data from fifo
always@(posedge clk)begin
if(rd_en && !empty)begin
rd_data<=sync_fifo[rd_ptr];
rd_ptr<=rd_ptr+1;
end
end
endmodule `
Testbench Code:
`module tb();
//input and output signals declaration
parameter data_width = 8;
reg [data_width-1:0]wr_data;
reg wr_en,rd_en,clk,rst;
wire [data_width-1:0]rd_data;
wire full,empty;
//module instantiation
sync_fifo_design dut(.wr_data(wr_data),.wr_en(wr_en),.rd_data(rd_data),.rd_en(rd_en),.full(full),.empty(empty),.clk(clk),.rst(rst));
//stimuli
initial begin
clk=0;
rst=1;
wr_en=0;
rd_en=0;
rst=0;
//writing values 5,10,15,20 into FIFO
@(posedge clk)wr_en=1;wr_data=3'b101;
@(posedge clk)wr_data=4'b1010;
@(posedge clk)wr_data=4'b1111;
@(posedge clk)wr_data=5'b10100;
@(posedge clk)wr_en=0;rd_en=1;
end
always
#1 clk=~clk;
initial begin
$monitor("wr_data =%d,wr_en=%b,rd_en=%b,rst=%b,rd_data=%d",wr_data,wr_en,rd_en,rst,rd_data);
$dumpfile("dump.vcd"); $dumpvars;
#30 $finish;
end
endmodule`
1 answer
Your current FIFO acts as a standard FIFO. What you desire is a First Word Fall Through (FWFT) FIFO or a showahead FIFO. Changing the rd_data to be combinational logic instead of registered logic is the way to do this, the modification would look like this:
//read data from fifo always@(posedge clk)begin if(rd_en && !empty)begin //rd_data<=sync_fifo[rd_ptr]; // this would yield a value next cc rd_ptr<=rd_ptr+1; end end // remove 'reg' from rd_data port and make a continuous assignment assign rd_data = sync_fifo[rd_ptr];
Changing the read enable (rd_en) net name to a read acknowledge (rd_ack) may be a more descriptive label in this case.
More information can be found at places like Eli Billauer's spin-off FPGA blog: https://www.01signal.com/using-ip/fpga-fifo/variants/
0 comment threads