# [SOLVED]Async FIFO simulation problem

Status
Not open for further replies.

#### stark43

##### Junior Member level 2
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

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 ,
);
parameter DATA_WIDTH = 8;
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: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.*/
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
end
end

always @(posedge read_clk or posedge reset) begin
if (reset) begin
end else begin
end
end else begin              // (next_can_read == 0)
end
end else begin
end else begin

end
end
end
end

///// CROSS-DOMAIN /////

.reset(reset),
.clk(write_clk),
);

// Synchronize write_ptr_grey_w into write_ptr_grey_r.
.reset(reset),
.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_write_clk = 0;
reg [7:0] tb_write_data = 0;
reg tb_write = 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

always begin
end

//Data send
always @(posedge tb_write_clk) begin

tb_write_data = tb_write_data + 1;
end

a = a +1;
if (a == 647) begin
end

if (a == 920) begin
end
end

asyncfifo DUT(
.reset(tb_reset),
.write_clk(tb_write_clk),
.write_data(tb_write_data),
.write(tb_write),
);

endmodule`

#### KlausST

##### Super Moderator
Staff member
Hi,

generally I don´t think it´s a good idea to rely on any device after 100ns from power up.

Consider to use internal or external RESET functionality.
While I can see some "reset" in your code, I can´t see it in the simulation.

Klaus

#### dpaul

Other than the reset thing, I do not understand the relationship between clk, read_clk and write_clk.
The code is written is such a way that reset signal is in sync with the clk clock domain. But it is async to the read_clk and write_clk domains.
You have not shown us how the reset looks in simulation.
All FIFO read and write side registers must be reset (bring the registers to a known state) before you can push data in to it or read out from it.

#### stark43

##### Junior Member level 2
Thanks for the replies. I added 100 ns reset as you said. I detected the problem. In the first read_clk pulse after the reset signal, FIFO tries to read data 0, but cannot read data 0 because it is not written. However, in the first write_clk pulse after the reset, it had to write the data to the 0 address of the buffer. Because the write condition is met.

##### Super Moderator
Staff member
You should wait for reset to deassert before attempting to write. Only write when can_write is high. You also shouldn't attempt to read until can_read of the FIFO is high.

In both these cases you are writing to a FIFO in reset and not ready and reading from a FIFO that has no data written to it or is not ready.

#### stark43

##### Junior Member level 2
You should wait for reset to deassert before attempting to write.
What do you mean by waiting? Do I need to activate write and read after a few cycles after reset? There are two conditions for FIFO to be able to write to the buffer (write and can_write). Even if I reset the parameters with reset it seems to be configured in the next cycle. Also, at the 2nd place I specified in the picture, can_read becomes 0 and I lose 1 data again, but can_read should stay at 1 unless the FIFO is empty. I'm stuck in these two places and I don't really understand, can you tell me your solution suggestions if possible?

#### KlausST

##### Super Moderator
Staff member
What do you mean by waiting? Do I need to activate write and read after a few cycles after reset?

We see that "read_clk" is active while "can_read" is LOW. This is not how it is meant to work.

What´s the meaning of "can_read"? When HIGH it tells that data is available to be read. So if no data is available it is LOW and then: don´t try to read data, don´t activate the read_clk.

Similar with "write"...

Klaus

#### stark43

##### Junior Member level 2

We see that "read_clk" is active while "can_read" is LOW. This is not how it is meant to work.

What´s the meaning of "can_read"? When HIGH it tells that data is available to be read. So if no data is available it is LOW and then: don´t try to read data, don´t activate the read_clk.

Similar with "write"...

Klaus
Hi Klaus, thank you for your interest. I've looked at many simulations for Async FIFO, this is the first time I've heard of the clock being stopped and I'll try it. But even if the clock is active, isn't the code address-controlled? If the can_read or can_write signal goes LOW it seems to control this by not increasing the write or read addresses. Am I thinking wrong sir?
--- Updated ---

If you want to look;

#### Attachments

• async_FIFO.zip
465.5 KB · Views: 12

#### KlausST

##### Super Moderator
Staff member
Hi,

These signals are used to "write" one byte into the FIFO. It may be at a constant data rate or a very non constant. (One data written after 100ns, then next data written the next week) = asynchrounous. Asynchronous to everything: like asynchronous to the previous edge, to the system clock, to the read clock....

And for sure you should only read data from the FIFO after you have data written into the FIFO.

Klaus

#### stark43

##### Junior Member level 2
Hi,

These signals are used to "write" one byte into the FIFO. It may be at a constant data rate or a very non constant. (One data written after 100ns, then next data written the next week) = asynchrounous. Asynchronous to everything: like asynchronous to the previous edge, to the system clock, to the read clock....

And for sure you should only read data from the FIFO after you have data written into the FIFO.

Klaus
You are right, my system clock is different from these clocks. Actually, my goal is to write the data from the camera after the frame valid signal comes and read it with a different clock. Then I will reset the FIFO when the frame valid signal comes. If can_read is active, I will enable read_clock, otherwise I will set it to zero. Similar with "write"...
Did I understand correctly, sir?

#### dpaul

Then I will reset the FIFO when the frame valid signal comes.
No, you reset the FIFO (registers) only initially, at the beginning or if for any other reason you need to do system reset.
Then as data comes in, you write in to it and as soon as valid data is available, you read out the FIFO.
You should have controllers both on the write side and read side that will control the writing to and reading out of the FIFO.

#### KlausST

##### Super Moderator
Staff member
Hi,

now it´s the first time you mention "camera" and "frame".
So basically you want to use a FIFO to buffer picture data.
Thus there should be a camera interface with a descripton of signals, their function and their timing.
I guess you rather want to adjust the FPGA to the camera than vice versa.

But the FIFO also has an output. Where does it go to? What is it´s requirement about signals and timing?

And I agree with dpaul. Usually you want to process picture data somehow. but with resetting the FIFO you rather "delete" some data ... and can´t be processed.

***
The FIFO may be a suitable solution...
...but with picture data coming from a camara using DMA or dual port memories may be an improvement.
Because that you can frame sync the data to memory location address.
just as an example: then you know that the top right corner picture data is always located at address 1023.

Often with picture data one uses two RAM buffers: let´s name them A and B.
* So first frame data from the camera is written to buffer A.
* Then with the frame sync signal the buffers are switched:
* the second frame becomes written into buffer B .. while the data in buffer A can be processed somehow.
* Then with the frame sync signal the buffers are switched:
* the third frame becomes written into buffer A .. while the data in buffer B can be processed somehow.
* and so on...

in either case_ processing the data needs to be faster than the frame period time

Klaus

#### stark43

##### Junior Member level 2
Hi sir,
Actually, I don't need to process the data, I'm only interested in the transmit side. My interface is MIPI CSI-2, maybe you have heard of it before or you are interested.
As you said, I need to save the incoming data in asynchronous FIFO and then pass it to the serializer module by adding some packets and waiting times at the beginning and end of the payload. I don't want to lose data, so I need to deal with the unknown value problem in the simulation output, as we talked about earlier. For this you told me to disable read_clk unless you are reading. Actually I thought I could configure write, read permission instead of disabling the clock. I'll try that and give you feedback, I hope it gets resolved. Thank you for your recommendation. As a newbie I am very happy to receive support.

--- Updated ---

No, you reset the FIFO (registers) only initially, at the beginning or if for any other reason you need to do system reset.
Then as data comes in, you write in to it and as soon as valid data is available, you read out the FIFO.
You should have controllers both on the write side and read side that will control the writing to and reading out of the FIFO.
Hi Dpaul,
Actually, I have external read and write permission signals and can_write and can_read signals determined by the FIFO being empty and full. Although I am satisfied with the general operation of FIFO, I have problems at 2 points.
1) I get X value in simulation output early in timing, we discussed this above.
2) FIFO pulls can_read low after about 620 ns as I have indicated in the image. It's not supposed to do this since the FIFO is not empty.
The article where the code is taken and the logic is explained: https://log.martinatkins.me/2020/06/07/verilog-async-fifo/
If you want to examine the output, I shared the file above.

Last edited:

#### dpaul

Ok, so as I understand it, can_write is akin to write_data_valid and can_read is like read_data_valid.
Then the read and write signals are akin to read_enable and write_enable.

Generally this is how you should operate a FIFO:
0. The the read_clock and write_clock be generated by the design as it should be.
1. After de-asserting the reset (done by the system at the very start), depending on the FIFO write controller logic, you can start pushing in data to the FIFO as soon as the camera sends in data.
2. You do not read immediately, but wait for a few write clock cycles, so that you have about 4 or 5 words written to the FIFO (many FIFOs have a write_data_count signal for this).
3. Only after that start reading the FIFO and continue reading, if and only if there is atleast 1 valid word written to it (but this again depends on the read controller design, one might stop reading earlier).
4. The write side controller should stop writing to the FIFO if the FIFO is full or almost full.

Are you doing the above steps?

btw - Why do you just not use a FIFO IP/Core that is supplied by most FPGA vendors? I am not discouraging you to learn about FIFO internals, but it is much easier to use.

Last edited:

#### stark43

##### Junior Member level 2
Ok, so as I understand it, can_write is akin to write_data_valid and can_read is like read_data_valid.
Then the read and write signals are akin to read_enable and write_enable.

Generally this is how you should operate a FIFO:
0. The the read_clock and write_clock be generated by the design as it should be.
1. After de-asserting the reset (done by the system at the very start), depending on the FIFO write controller logic, you can start pushing in data to the FIFO as soon as the camera sends in data.
2. You do not read immediately, but wait for a few write clock cycles, so that you have about 4 or 5 words written to the FIFO (many FIFOs have a write_data_count signal for this).
3. Only after that start reading the FIFO and continue reading, if and only if there is atleast 1 valid word written to it (but this again depends on the read controller design, one might stop reading earlier).
4. The write side controller should stop writing to the FIFO if the FIFO is full or almost full.

Are you doing the above steps?

btw - Why do you just not use a FIFO IP/Core that is supplied by most FPGA vendors? I am not discouraging you to learn about FIFO internals, but it is much easier to use.
Thanks, I'll try your advice and give feedback. You are right IP is much easier to use, even CSI-2 has IP. But my goal is not only to do the project, but also to learn, so I will be stubborn about it. Thanks to these support groups, I do not lose my confidence, I am grateful to you for that. I guess what's under the hood makes me even more excited than the car

#### KlausST

##### Super Moderator
Staff member
Hi,

2) FIFO pulls can_read low after about 620 ns as I have indicated in the image. It's not supposed to do this since the FIFO is not empty.
I guess this is the result of the "illegal read" while the "can_read" signal says "don´t read".

Imagine a post office. When nobody is in the post office the sign says "closed" i.e. "don´t write" ... but you ignore this and throw a parcel over the fence. It get´s not stored correctly. So when someone wants to pick the parcel, nobody knows where it is.

Or the more electronics way:
The FIFO is a memory with address. There are two pointers for addressing. One is the "write_pointer" the other is the "read_pointer".
* Initially both pointers are zero.
* then you fill in the first data --> WP = 1
* since WP = 1 and RP = 0 the logic knows that there is data stored.
* now you can read and RP becomes 1
* since RP = WP the logic knows there is no data stored.
(btw: usually a FIFO with n locations can only store n-1 data)

***
* both pointers are zero
* you ignore the "don´t read"... increment the RP to 1 (by performing the READ from addres 0)
* so WP = 0 and RP = 1 .. this is the condition for FIFO is FULL
* So when you perform the next (illegal or not) READ it wants to read from RP = 1 .. but your simulator knows that at this location there is no valid data (no data has been store into adress 1 before). Thus it shows the "X".
(A real FIFO will output random data ... also known ans "X")

Long story short: So my and ads-ee´s recommendation:
* don´t write when signal "can_write" is LOW
These are the rules to operate a FIFO correctly. Don´t be surprised of malfunction when not keeping on that rules.

Klaus

#### stark43

##### Junior Member level 2
I understand asynchronous FIFO better, I'll go and review what you said in simulation step by step, thank you both, I'm closing the issue as solved, see you on other issues, have a nice day.

Status
Not open for further replies.