ohmkara 1.0

a technical blog.

Archive for the ‘hdl’ Category

verilog synchronous fifo (code)

with 3 comments

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
Advertisements

Written by deepak

March 29, 2009 at 9:28 am

Posted in hdl

Tagged with