This repository was archived by the owner on Jan 5, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 218
Async FIFO Output is Broken when FIFO Depth is Set to 2 #296
Copy link
Copy link
Open
Description
Description
I found this when I was fixing cdc issue for fast servo port for linien. I used an async fifo for cdc purpose.
Here is where I made the change in fast-servo.
https://git.m-labs.hk/M-Labs/nix-servo/commit/87059eef2b7316dbdde7867c134bd843a66f8d85
self.cdc_fifo.sink.stb & self.cdc_fifo.source.ack are always high during operation.
https://git.m-labs.hk/M-Labs/nix-servo/src/commit/77643909efdad21f518d9192231188325f7296b2/fast-servo/linien-gateware/cores/dac.py#L52-L55
I connected the fast servo dac output to an oscilloscope and I observed that
- Async FIFO Depth = 2: DAC Modulating waveform was periodically broken.
- Async FIFO Depth = 4: DAC Modulating waveform looked good.
Related AsyncFIFO Migen Module
Lines 177 to 234 in c19ae9f
| class AsyncFIFO(Module, _FIFOInterface): | |
| """Asynchronous FIFO (first in, first out) | |
| Read and write interfaces are accessed from different clock domains, | |
| named `read` and `write`. Use `ClockDomainsRenamer` to rename to | |
| other names. | |
| {interface} | |
| """ | |
| __doc__ = __doc__.format(interface=_FIFOInterface.__doc__) | |
| def __init__(self, width, depth): | |
| _FIFOInterface.__init__(self, width, depth) | |
| ### | |
| depth_bits = log2_int(depth, True) | |
| produce = ClockDomainsRenamer("write")(GrayCounter(depth_bits+1)) | |
| consume = ClockDomainsRenamer("read")(GrayCounter(depth_bits+1)) | |
| self.submodules += produce, consume | |
| self.comb += [ | |
| produce.ce.eq(self.writable & self.we), | |
| consume.ce.eq(self.readable & self.re) | |
| ] | |
| produce_rdomain = Signal(depth_bits+1) | |
| produce.q.attr.add("no_retiming") | |
| self.specials += MultiReg(produce.q, produce_rdomain, "read") | |
| consume_wdomain = Signal(depth_bits+1) | |
| consume.q.attr.add("no_retiming") | |
| self.specials += MultiReg(consume.q, consume_wdomain, "write") | |
| if depth_bits == 1: | |
| self.comb += self.writable.eq((produce.q[-1] == consume_wdomain[-1]) | |
| | (produce.q[-2] == consume_wdomain[-2])) | |
| else: | |
| self.comb += [ | |
| self.writable.eq((produce.q[-1] == consume_wdomain[-1]) | |
| | (produce.q[-2] == consume_wdomain[-2]) | |
| | (produce.q[:-2] != consume_wdomain[:-2])) | |
| ] | |
| self.comb += self.readable.eq(consume.q != produce_rdomain) | |
| storage = Memory(self.width, depth) | |
| self.specials += storage | |
| wrport = storage.get_port(write_capable=True, clock_domain="write") | |
| self.specials += wrport | |
| self.comb += [ | |
| wrport.adr.eq(produce.q_binary[:-1]), | |
| wrport.dat_w.eq(self.din), | |
| wrport.we.eq(produce.ce) | |
| ] | |
| rdport = storage.get_port(clock_domain="read") | |
| self.specials += rdport | |
| self.comb += [ | |
| rdport.adr.eq(consume.q_next_binary[:-1]), | |
| self.dout.eq(rdport.dat_r) | |
| ] |
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels