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)