stark43
Member level 1
Hello, I'm interested in asynchronous FIFO, I understood the logic and used ready-made code. But I'm losing the first 3 data, I think it's because can_write and can_read are not stable, but I can't understand why. I looked many times and couldn't understand the problem, I wanted to consult you
TEST BENCH
SVG:
//Cross domain
module crossdomain #(parameter SIZE = 1) (
input reset,
input clk,
input [SIZE-1:0] data_in,
output reg [SIZE-1:0] data_out
);
reg [SIZE-1:0] data_tmp;
always @(posedge clk) begin
if (reset) begin
{data_out, data_tmp} <= 0;
end else begin
{data_out, data_tmp} <= {data_tmp, data_in};
end
end
endmodule
// Async FIFO implementation
module asyncfifo(
input reset,
input write_clk,
input write,
input [DATA_WIDTH-1:0] write_data,
output reg can_write ,
input read_clk,
input read,
output reg [DATA_WIDTH-1:0] read_data,
output reg can_read
);
parameter DATA_WIDTH = 8;
parameter BUFFER_ADDR_WIDTH = 10;
parameter BUFFER_SIZE = 2 ** BUFFER_ADDR_WIDTH;
reg [DATA_WIDTH-1:0] buffer[BUFFER_SIZE-1:0];
///// WRITE CLOCK DOMAIN /////
reg [BUFFER_ADDR_WIDTH:0] write_ptr; //wrap-around bit eklenmis hali
wire [BUFFER_ADDR_WIDTH-1:0] write_addr = write_ptr[BUFFER_ADDR_WIDTH-1:0];
reg [BUFFER_ADDR_WIDTH:0] write_ptr_grey_w;
wire [BUFFER_ADDR_WIDTH:0] read_ptr_grey_w;
wire [BUFFER_ADDR_WIDTH:0] next_write_ptr = write_ptr + 1;
wire [BUFFER_ADDR_WIDTH:0] next_write_ptr_grey_w = (next_write_ptr >> 1) ^ next_write_ptr;
/*Okuma ve yazma adresleri aynı ancak MSB'ler (sarma bitleri) farklıysa arabelleğimiz doludur. Burada gri kod sürümlerini karşılaştırıyoruz, böylece okuma işaretçisinin etki alanları arası senkronize kopyasını kullanabiliriz.*/
wire current_can_write = write_ptr_grey_w != { ~read_ptr_grey_w[BUFFER_ADDR_WIDTH:BUFFER_ADDR_WIDTH-1], read_ptr_grey_w[BUFFER_ADDR_WIDTH-2:0] };
wire next_can_write = next_write_ptr_grey_w != { ~read_ptr_grey_w[BUFFER_ADDR_WIDTH:BUFFER_ADDR_WIDTH-1], read_ptr_grey_w[BUFFER_ADDR_WIDTH-2:0] };
always @(posedge write_clk or posedge reset) begin
if (reset) begin
write_ptr <= 0;
write_ptr_grey_w <= 0;
can_write <= 1;
end else begin
if (write && can_write) begin //FIFO bos degilse ve yazma izni varsa siradaki pointer degerlerini güncellemesi icin yazilmişs if blogu
write_ptr <= next_write_ptr;
write_ptr_grey_w <= next_write_ptr_grey_w; //Arttirilmiş write pointer'in gray hali, amac degisen write pointer'i gray'e cevirmek
can_write <= next_can_write; //can_write --> next_can_write olmasi demek eger yazilabilir sartlar tutuyorsa siradaki pointer icin yazilabilir olup olmadigini günceller (gray haline bakarak)
end else begin
can_write <= current_can_write; //write ve can_write sartlari tutmuyorsa degeri güncellemiyor
end
end
end
always @(posedge write_clk) begin
if (write && can_write) begin
buffer[write_addr] <= write_data;
end
end
///// READ CLOCK DOMAIN /////
reg [BUFFER_ADDR_WIDTH:0] read_ptr = 0;
wire [BUFFER_ADDR_WIDTH-1:0] read_addr = read_ptr[BUFFER_ADDR_WIDTH-1:0];
reg [BUFFER_ADDR_WIDTH:0] read_ptr_grey_r;
wire [BUFFER_ADDR_WIDTH:0] write_ptr_grey_r;
wire [BUFFER_ADDR_WIDTH-1:0] next_read_ptr = read_ptr + 1; /*orjinali böyleydi wire [BUFFER_ADDR_WIDTH:0] next_read_ptr = read_ptr + 1;*/
wire [BUFFER_ADDR_WIDTH:0] next_read_ptr_grey_r = (next_read_ptr >> 1) ^ next_read_ptr;
wire current_can_read = read_ptr_grey_r != write_ptr_grey_r;
wire next_can_read = next_read_ptr_grey_r != write_ptr_grey_r;
always @(posedge read_clk or posedge reset) begin
if (reset) begin
read_ptr <= 0;
read_ptr_grey_r <= 0;
read_data <= 0;
can_read <= 0;
end else begin
if (read) begin
if (can_read) begin
read_ptr <= next_read_ptr;
read_ptr_grey_r <= next_read_ptr_grey_r;
end
can_read <= next_can_read;
if (next_can_read) begin
read_data <= buffer[next_read_ptr];
end else begin // (next_can_read == 0)
read_data <= 0;
end
end else begin
can_read = current_can_read;
if (current_can_read) begin
read_data <= buffer[read_addr];
end else begin
read_data <= 0;
end
end
end
end
///// CROSS-DOMAIN /////
// Synchronize read_ptr_grey_r into read_ptr_grey_w.
crossdomain #(.SIZE(BUFFER_ADDR_WIDTH+1)) read_ptr_grey_sync (
.reset(reset),
.clk(write_clk),
.data_in(read_ptr_grey_r),
.data_out(read_ptr_grey_w)
);
// Synchronize write_ptr_grey_w into write_ptr_grey_r.
crossdomain #(.SIZE(BUFFER_ADDR_WIDTH+1)) write_ptr_grey_sync (
.reset(reset),
.clk(read_clk),
.data_in(write_ptr_grey_w),
.data_out(write_ptr_grey_r)
);
endmodule
TEST BENCH
SVG:
`timescale 1ns / 1ps
module tb_async_FIFO();
reg tb_reset = 0;
reg tb_read_clk = 0;
reg tb_write_clk = 0;
reg [7:0] tb_write_data = 0;
reg tb_write = 1;
reg tb_read = 1;
reg [9:0] a = 0;
initial begin
tb_reset = 1;
#2
tb_reset = 0;
end
//pixel clock
always begin
#21 tb_write_clk = ~tb_write_clk;
end
//read clock
always begin
#24 tb_read_clk = ~tb_read_clk;
end
//Data send
always @(posedge tb_write_clk) begin
tb_write_data = tb_write_data + 1;
end
always @(posedge tb_read_clk) begin
a = a +1;
if (a == 647) begin
tb_read = 0;
end
if (a == 920) begin
tb_read = 1;
end
end
asyncfifo DUT(
.reset(tb_reset),
.write_clk(tb_write_clk),
.write_data(tb_write_data),
.write(tb_write),
.read(tb_read),
.read_clk(tb_read_clk)
);
endmodule