FPGA Introduction Course Training #09 – FIFO in Verilog

YouTube-Channel-Art-Template.png


fpga introduction course training #9 - 1.PNG
– FIFO는 first-in-first-out의 약자이다.
– FIFO는 cross-clock domain간 통신 또는 회로 동기화에 사용할 수 있음. 한 회로가 데이터를 생성하고 (producer), 다른 회로가 데이터를 차례로 소모하는 (consumer) 경우에 사용할 수 있다.
– FIFO는 두 개의 상태를 갖는다. FIFO는 full 또는 empty의 상태를 가짐.
– FIFO는 data_in, wr_en, rd_en을 input으로 갖고, data_out, full, empty를 output으로 갖는다.
– FIFO는 내부적으로 dual port RAM을 갖는다. 한 클럭에서도 동시에 읽기와 쓰기가 가능하므로 dual port RAM을 사용한다.
– FIFO는 추가로 read pointer와 write pointer를 갖는다. 이를 사용해 어디에 쓸 것인지, 어디에서 읽을 것인지 알 수 있다.

//this code is provided by the development channel
//https://www.youtube.com/channel/UC1ptV25-NEHRIEnM1kXMCrQ
//thank you, Leonardo!
`timescale 1ns / 1ps
module fifoSynch #(parameter NUM_BITS=8, DEPTH=8)
    (
        input rst_n,
        input clk,
        input rd_en,
        input wr_en,
        input [(NUM_BITS-1):0] fifo_in,
        output reg [(NUM_BITS-1):0] fifo_out,
        output empty,
        output full,
        output reg [(clogb2(DEPTH)):0] fifo_counter // Able to count more than depth
    );
    
    // Read and write fifo pointers (We put -2, because on the case of DEPTH=8
    // clog2(DEPTH) = 3, then 1:0, 2 bits, we count from 0 to 3
    reg [(clogb2(DEPTH)-1):0] rd_ptr, wr_ptr;
    
    // Declare the fifo memory (RAM that allow read and write at the same time)
    // reg [7:0] fifo_mem[3:0], create an array of 4 elements of 8 bits
    reg[(NUM_BITS-1):0] fifo_mem[(DEPTH-1):0];
    
    // Combinational part that calculate the empty/full flags
    assign empty = (fifo_counter==0);
    assign full = (fifo_counter==DEPTH);
    
    // Sequential circuit that will handle the fifo_counter, which is used to 
    // detect if the fifo is empty or full.
    always @(posedge clk or negedge rst_n)
    begin
        if (~rst_n)
            fifo_counter <= 0;
        else if( (!full && wr_en) && ( !empty && rd_en ) ) 
            fifo_counter <= fifo_counter;     // If read and write don't change counter          
        else if (!full && wr_en)  
            fifo_counter <= fifo_counter + 1; // Only write increment            
        else if (!empty && rd_en)  
            fifo_counter <= fifo_counter - 1; // Only read decrement                                          
    end
    
    // Sequential circuit to handle reading on the fifo
    always @( posedge clk or negedge rst_n)
    begin
        if( ~rst_n )
            fifo_out <= 0;
        else
            begin
              // Give some data if not empty and we want to read
              if ( !empty && rd_en )
                begin
                    fifo_out <= fifo_mem[rd_ptr];
                    // synthesis translate_off                    
                    $display("Popping value: %d at %t",fifo_mem[rd_ptr],$time);                    
                    // synthesis translate_on
                end                    
                                 
                                                       
            end
    end
    
    // Sequential circuit to handle writing to the fifo
    always @(posedge clk)
    begin    
       if (!full && wr_en)
        begin
            fifo_mem[ wr_ptr ] <= fifo_in;
            // synthesis translate_off                    
            $display("Pushing value: %d at %t",fifo_in,$time);                    
            // synthesis translate_on
        end                            
    end
    
    // Sequential circut to handle the read/write pointers
    always@(posedge clk or negedge rst_n)
    begin
        if( ~rst_n )
        begin
            // In the beginning the pointers are the same
            wr_ptr <= 0;
            rd_ptr <= 0;
        end
        else
        begin
            // We're not full and someone want to write, so we increment the write pointer
            if( !full && wr_en )
                wr_ptr <= wr_ptr + 1;              
            
            // We're not empty and someone want to read, so we decrement the read pointer
            if( !empty && rd_en )
                rd_ptr <= rd_ptr + 1;          
        end    
    end    
    
    /* 
        Calculate the ceil of log2, this is used to know the number of bits needed to
        map a certain depth (need to be power 2). This function will be called on 
        compilation-time
    */         
    function integer clogb2;
    input [31:0] depth;
        begin
            depth = depth - 1;
            for(clogb2=0; depth>0; clogb2=clogb2+1)
                depth = depth >> 1;
        end
    endfunction
endmodule

Advertisements
Tagged with: , , , , , , , ,
Posted in FPGA

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

누적 방문자 수
  • 103,571 hits
%d bloggers like this: