Archive for the ‘hdl’ Category
verilog synchronous fifo (code)
I would have preferred a log2() user defined function and fifo depth parameter as a decimal integer. But icarus verilog does not seem to let me — hence the inelegance for now…
///////////////////////////////////////////////
// Author: (28/03/2009 08:54)
// Module: sync_fifo.v
// Project:
// Description: Synchronous FIFO
// data output (dout) is un-registered.
// Version: 1.0
/////////////////////////////////////////////////
module sync_fifo
#(
parameter DATA_WIDTH = 8,
parameter LOG2_DEPTH = 3 // i.e. fifo depth=2**LOG2_DEPTH
)
(
input [DATA_WIDTH-1:0] din,
input wr_en,
input rd_en,
output [DATA_WIDTH-1:0] dout,
output full,
output empty,
input clk,
input reset
);
parameter MAX_COUNT = 2**LOG2_DEPTH;
reg [LOG2_DEPTH-1 : 0] rd_ptr;
reg [LOG2_DEPTH-1 : 0] wr_ptr;
reg [DATA_WIDTH-1 : 0] mem[MAX_COUNT-1 : 0]; //memory size: 2**LOG2_DEPTH
reg [LOG2_DEPTH : 0] depth_cnt;
always @(posedge clk) begin
if(reset) begin
wr_ptr <= 'h0;
rd_ptr <= 'h0;
end // end if
else begin
if(wr_en)begin
wr_ptr <= wr_ptr+1;
end
if(rd_en)
rd_ptr <= rd_ptr+1;
end //end else
end//end always
assign empty= (depth_cnt=='h0);
assign full = (depth_cnt==MAX_COUNT);
//comment if you want a registered dout
assign dout = rd_en ? mem[rd_ptr]:'h0;
always @(posedge clk) begin
if (wr_en)
mem[wr_ptr] <= din;
end //end always
//uncomment if you want a registered dout
//always @(posedge clk) begin
// if (reset)
// dout <= 'h0;
// else if (rd_en)
// dout <= mem[rd_ptr];
//end
always @(posedge clk) begin
if (reset)
depth_cnt <= 'h0;
else begin
case({rd_en,wr_en})
2'b10 : depth_cnt <= depth_cnt-1;
2'b01 : depth_cnt <= depth_cnt+1;
endcase
end //end else
end //end always
endmodule
errata / addendum:
A better synchronous fifo might be — code below…
</pre> /////////////////////////////////////////////// // Author: Deepak (28/03/2009 08:54) // Module: fifo.v // Project: // Description: Synchronous FIFO // data output (dout) is un-registered. // Version: 1.1 (not icarus verilog compatible) // /////////////////////////////////////////////// module sync_fifo #( parameter DATA_WIDTH = 8, parameter DEPTH = 8</pre> ) ( input [DATA_WIDTH-1:0] din, input wr_en, input rd_en, output [DATA_WIDTH-1:0] dout, output reg full, output reg empty, input clk, input reset ); function integer log2; input integer n; begin log2 = 0; while(2**log2 < n) begin log2=log2+1; end end endfunction parameter ADDR_WIDTH = log2(DEPTH); reg [ADDR_WIDTH : 0] rd_ptr; // note MSB is not really address reg [ADDR_WIDTH : 0] wr_ptr; // note MSB is not really address wire [ADDR_WIDTH-1 : 0] wr_loc; wire [ADDR_WIDTH-1 : 0] rd_loc; reg [DATA_WIDTH-1 : 0] mem[DEPTH-1 : 0]; assign wr_loc = wr_ptr[ADDR_WIDTH-1 : 0]; assign rd_loc = rd_ptr[ADDR_WIDTH-1 : 0]; always @(posedge clk) begin if(reset) begin wr_ptr <= 'h0; rd_ptr <= 'h0; end // end if else begin if(wr_en & (~full))begin wr_ptr <= wr_ptr+1; end if(rd_en & (~empty)) rd_ptr <= rd_ptr+1; end //end else end//end always //empty if all the bits of rd_ptr and wr_ptr are the same. //full if all bits except the MSB are equal and MSB differes always @(rd_ptr or wr_ptr)begin //default catch-alls empty <= 1'b0; full <= 1'b0; if(rd_ptr[ADDR_WIDTH-1:0]==wr_ptr[ADDR_WIDTH-1:0])begin if(rd_ptr[ADDR_WIDTH]==wr_ptr[ADDR_WIDTH]) empty <= 1'b1; else full <= 1'b1; end//end if end//end always always @(posedge clk) begin if (wr_en) mem[wr_loc] <= din; end //end always //comment if you want a registered dout assign dout = rd_en ? mem[rd_loc]:'h0; //uncomment if you want a registered dout //always @(posedge clk) begin // if (reset) // dout <= 'h0; // else if (rd_en) // dout <= mem[rd_ptr]; //end endmodule