104 lines
2.1 KiB
Verilog
104 lines
2.1 KiB
Verilog
/*
|
|
* This file is based on "Asynchronous FIFO" by Alex Claros F.,
|
|
* itself based on the article "Asynchronous FIFO in Virtex-II FPGAs"
|
|
* by Peter Alfke.
|
|
*/
|
|
|
|
module asfifo #(
|
|
parameter data_width = 8,
|
|
parameter address_width = 4,
|
|
parameter fifo_depth = (1 << address_width)
|
|
) (
|
|
/* Read port */
|
|
output reg [data_width-1:0] data_out,
|
|
output reg empty,
|
|
input read_en,
|
|
input clk_read,
|
|
|
|
/* Write port */
|
|
input [data_width-1:0] data_in,
|
|
output reg full,
|
|
input write_en,
|
|
input clk_write,
|
|
|
|
/* Asynchronous reset */
|
|
input rst
|
|
);
|
|
|
|
reg [data_width-1:0] mem[fifo_depth-1:0];
|
|
wire [address_width-1:0] write_index, read_index;
|
|
wire equal_addresses;
|
|
wire write_en_safe, read_en_safe;
|
|
wire set_status, clear_status;
|
|
reg status;
|
|
wire preset_full, preset_empty;
|
|
|
|
reg [data_width-1:0] data_out0;
|
|
|
|
always @(posedge clk_read) begin
|
|
data_out0 <= mem[read_index];
|
|
data_out <= data_out0;
|
|
end
|
|
|
|
always @(posedge clk_write) begin
|
|
if(write_en & !full)
|
|
mem[write_index] <= data_in;
|
|
end
|
|
|
|
assign write_en_safe = write_en & ~full;
|
|
assign read_en_safe = read_en & ~empty;
|
|
|
|
asfifo_graycounter #(
|
|
.width(address_width)
|
|
) counter_write (
|
|
.gray_count(write_index),
|
|
.ce(write_en_safe),
|
|
.rst(rst),
|
|
.clk(clk_write)
|
|
);
|
|
|
|
asfifo_graycounter #(
|
|
.width(address_width)
|
|
) counter_read (
|
|
.gray_count(read_index),
|
|
.ce(read_en_safe),
|
|
.rst(rst),
|
|
.clk(clk_read)
|
|
);
|
|
|
|
assign equal_addresses = (write_index == read_index);
|
|
|
|
assign set_status = (write_index[address_width-2] ~^ read_index[address_width-1]) &
|
|
(write_index[address_width-1] ^ read_index[address_width-2]);
|
|
|
|
assign clear_status = ((write_index[address_width-2] ^ read_index[address_width-1]) &
|
|
(write_index[address_width-1] ~^ read_index[address_width-2]))
|
|
| rst;
|
|
|
|
always @(posedge clear_status, posedge set_status) begin
|
|
if(clear_status)
|
|
status <= 1'b0;
|
|
else
|
|
status <= 1'b1;
|
|
end
|
|
|
|
assign preset_full = status & equal_addresses;
|
|
|
|
always @(posedge clk_write, posedge preset_full) begin
|
|
if(preset_full)
|
|
full <= 1'b1;
|
|
else
|
|
full <= 1'b0;
|
|
end
|
|
|
|
assign preset_empty = ~status & equal_addresses;
|
|
|
|
always @(posedge clk_read, posedge preset_empty) begin
|
|
if(preset_empty)
|
|
empty <= 1'b1;
|
|
else
|
|
empty <= 1'b0;
|
|
end
|
|
|
|
endmodule
|