This is a rewrite of the "basic fifo".  The basic fifo can hold 16
entries and requires input and output clocks to be the same.  The sync
fifo allows input and output clocks to be in different domains.  It
uses graycode counters for glitch-free crossing of domains for head
and tail pointers.  The fifo can only store 15 entries in the memory
buffer, but since the output is registered, it can technically hold
16.  Reset is async so that we don't have to care which clock domain
the signal came from.



// Sync fifo
// Copyright 2005, Timothy Miller
// LGPL license


module sync_fifo(
    reset,

    in_clock,
    data_in,
    enq,
    full,

    out_clock,
    data_out,
    valid_out,
    deq,
    empty
);

parameter fifo_width = 32;
// fifo depth is hard-wired to 16

input in_clock, out_clock, reset;

input [fifo_width-1:0] data_in;
input enq;
output full;
reg full;

output [fifo_width-1:0] data_out;
reg [fifo_width-1:0] data_out;
output valid_out;
reg valid_out;
input deq;
output empty;
reg empty;



reg [fifo_width-1:0] fifo_data [0:15];
reg [3:0] head0, tail0;
reg [3:0] head1, tail1, tail2;

wire [3:0] tail3 = next_gray_code(tail2);

// accept input
wire next_full = tail2 == head0;
wire is_full = tail1 == head0;
always @(posedge in_clock or posedge reset) begin
    if (reset) begin
        tail0 <= 0;
        tail1 <= 1;
        tail2 <= 3;
        full <= 0;
    end else begin
        if (!full && enq) begin
            // We can only enqueue when not full
            fifo_data[tail0] <= data_in;
            tail0 <= tail1;
            tail1 <= tail2;
            tail2 <= tail3; //next_gray_code(tail2);

            // We have to compute if it's full on next cycle
            full <= next_full;

            // It might not really be full if we're dequeueing,
            // But we don't really care.  Setting full early
            // will not result in data loss.
        end else begin
            full <= is_full;
        end
    end
end

wire [3:0] head2 = next_gray_code(head1);

// provide output
wire next_empty = head1 == tail0;
wire is_empty = head0 == tail0;
always @(posedge out_clock or posedge reset) begin
    if (reset) begin
        valid_out <= 0;
        data_out <= 0;
        head0 <= 0;
        head1 <= 1;
    end else begin
        // If no valid out or we're dequeueing, we want to grab
        // the next data.  If we're empty, we don't get valid_out,
        // so we don't care if it's garbage.
        if (!valid_out || deq) begin
            data_out <= fifo_data[head0];
        end

        if (!valid_out || deq) begin
            // Yes, can have valid_out and empty at the same time.
            // empty just means there are 16 entries free.
            empty <= next_empty;
        end else begin
            empty <= is_empty;
        end
        // In either case, empty could be 'wrong' if an enq happens at
        // the same time.  Fortunately, data_out functions as a 17th
        // entry, and of course, you should never design anything that
        // assumes 'empty' means you can blindly euqueue 16 entries
        // (ie. without paying attention to 'full').

        if (!is_empty) begin
            if (!valid_out || deq) begin
                head0 <= head1;
                head1 <= head2; //next_gray_code(head1);
            end
            valid_out <= 1;
        end else begin
            if (deq) valid_out <= 0;
        end
    end
end



// This should turn into four LUT RAMs, which is the best you can get
// from an FPGA for this function.
function [3:0] next_gray_code;
input [3:0] I;
begin
    case (I)
         0: next_gray_code =  1;
         1: next_gray_code =  3;
         3: next_gray_code =  2;
         2: next_gray_code =  6;
         6: next_gray_code =  7;
         7: next_gray_code =  5;
         5: next_gray_code =  4;
         4: next_gray_code = 12;
        12: next_gray_code = 13;
        13: next_gray_code = 15;
        15: next_gray_code = 14;
        14: next_gray_code = 10;
        10: next_gray_code = 11;
        11: next_gray_code =  9;
         9: next_gray_code =  8;
         8: next_gray_code =  0;
    endcase
end
endfunction

endmodule

_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)

Reply via email to