alexforencich / verilog-axis

Verilog AXI stream components for FPGA implementation
MIT License
710 stars 220 forks source link

Questions about Clock Domain Crossing in axis_async_fifo #22

Open Yuan-Mao opened 2 years ago

Yuan-Mao commented 2 years ago

Hi I am looking at this specific commit 40acee1bc59c8091c65cedfa470cc16cbce8e6bb.

The module "axis_async_fifo" has a write clock domain (driven by s_clk) and a read clock domain (driven by m_clk). To my understanding, the CDC strategy used in the write domain -> read domain direction is a mux-controlled CDC, i.e., the read domain will only accept the gray pointer from write domain if the update signal generated from write domain is propagated from write to read domain. Also, any updates to the write pointer will be delayed until the ACK for the update signal is propagated back to the write domain.

Above is the case for write -> read direction. However, in read -> write direction, it seems to me we only use 2-flop synchronizer (without any ACK signal) to sync the read pointer from read to write domain.

Q1: Is there a reason why the ACK signal is needed in the write -> read direction? Can't we just simply use 2-flop synchronizer like we do in the read -> write direction?

Q2: Why the pipeline registers in "axis_async_fifo" are needed to sync the read output from the memory? Isn't the read result already synced to the read clock? (based on my assumption that the memory is 1r1w synchronous with separate read/write clocks)

Thanks!

alexforencich commented 2 years ago

The handshaking is required because in frame FIFO mode, the pointer does not increment continuously, instead it jumps by a whole frame size. This rather defeats the purpose of the gray code, which really only works properly when the pointers increment by 1 at a time. This has caused issues in hardware - under certain conditions, with the right skew, the read logic can incorrectly assume that the FIFO is empty and deassert tvalid in the middle of a frame, resulting in the TX MAC terminating the frame. The fix was to switch to the handshake synchronizer.

The pipeline registers are not for synchronization, they are meant to be pulled in to the RAM as pipeline registers to improve timing performance. This is particularly important for large FIFOs that get constructed from a cascade chain of multiple BRAMs or URAMs. As a result, the depth of this pipeline is configurable so it can be adjusted to best match the RAM configuration needed to implement the FIFO on the target device.