1 """First-in first-out queues."""
4 from ..asserts
import *
5 from .._utils
import log2_int
, deprecated
6 from .coding
import GrayEncoder
, GrayDecoder
7 from .cdc
import FFSynchronizer
, AsyncFFSynchronizer
10 __all__
= ["FIFOInterface", "SyncFIFO", "SyncFIFOBuffered", "AsyncFIFO", "AsyncFIFOBuffered"]
20 Bit width of data entries.
22 Depth of the queue. If zero, the FIFO cannot be read from or written to.
31 Asserted if there is space in the queue, i.e. ``w_en`` can be asserted to write
34 Write strobe. Latches ``w_data`` into the queue. Does nothing if ``w_rdy`` is not asserted.
36 Number of unread entries.
39 Output data. {r_data_valid}
41 Asserted if there is an entry in the queue, i.e. ``r_en`` can be asserted to read
44 Read strobe. Makes the next entry (if any) available on ``r_data`` at the next cycle.
45 Does nothing if ``r_rdy`` is not asserted.
47 Number of unread entries.
51 __doc__
= _doc_template
.format(description
="""
52 Data written to the input interface (``w_data``, ``w_rdy``, ``w_en``) is buffered and can be
53 read at the output interface (``r_data``, ``r_rdy``, ``r_en`). The data entry written first
54 to the input also appears first on the output.
57 r_data_valid
="The conditions in which ``r_data`` is valid depends on the type of the queue.",
60 First-word fallthrough. If set, when ``r_rdy`` rises, the first entry is already
61 available, i.e. ``r_data`` is valid. Otherwise, after ``r_rdy`` rises, it is necessary
62 to strobe ``r_en`` for ``r_data`` to become valid.
67 def __init__(self
, *, width
, depth
, fwft
):
68 if not isinstance(width
, int) or width
< 0:
69 raise TypeError("FIFO width must be a non-negative integer, not {!r}"
71 if not isinstance(depth
, int) or depth
< 0:
72 raise TypeError("FIFO depth must be a non-negative integer, not {!r}"
78 self
.w_data
= Signal(width
, reset_less
=True)
79 self
.w_rdy
= Signal() # writable; not full
81 self
.w_level
= Signal(range(depth
+ 1))
83 self
.r_data
= Signal(width
, reset_less
=True)
84 self
.r_rdy
= Signal() # readable; not empty
86 self
.r_level
= Signal(range(depth
+ 1))
89 def _incr(signal
, modulo
):
90 if modulo
== 2 ** len(signal
):
93 return Mux(signal
== modulo
- 1, 0, signal
+ 1)
96 class SyncFIFO(Elaboratable
, FIFOInterface
):
97 __doc__
= FIFOInterface
._doc
_template
.format(
99 Synchronous first in, first out queue.
101 Read and write interfaces are accessed from the same clock domain. If different clock domains
102 are needed, use :class:`AsyncFIFO`.
106 First-word fallthrough. If set, when the queue is empty and an entry is written into it,
107 that entry becomes available on the output on the same clock cycle. Otherwise, it is
108 necessary to assert ``r_en`` for ``r_data`` to become valid.
111 For FWFT queues, valid if ``r_rdy`` is asserted. For non-FWFT queues, valid on the next
112 cycle after ``r_rdy`` and ``r_en`` have been asserted.
118 def __init__(self
, *, width
, depth
, fwft
=True):
119 super().__init
__(width
=width
, depth
=depth
, fwft
=fwft
)
121 self
.level
= Signal(range(depth
+ 1))
123 def elaborate(self
, platform
):
133 self
.w_rdy
.eq(self
.level
!= self
.depth
),
134 self
.r_rdy
.eq(self
.level
!= 0),
135 self
.w_level
.eq(self
.level
),
136 self
.r_level
.eq(self
.level
),
139 do_read
= self
.r_rdy
& self
.r_en
140 do_write
= self
.w_rdy
& self
.w_en
142 storage
= Memory(width
=self
.width
, depth
=self
.depth
)
143 w_port
= m
.submodules
.w_port
= storage
.write_port()
144 r_port
= m
.submodules
.r_port
= storage
.read_port(
145 domain
="comb" if self
.fwft
else "sync", transparent
=self
.fwft
)
146 produce
= Signal(range(self
.depth
))
147 consume
= Signal(range(self
.depth
))
150 w_port
.addr
.eq(produce
),
151 w_port
.data
.eq(self
.w_data
),
152 w_port
.en
.eq(self
.w_en
& self
.w_rdy
),
155 m
.d
.sync
+= produce
.eq(_incr(produce
, self
.depth
))
158 r_port
.addr
.eq(consume
),
159 self
.r_data
.eq(r_port
.data
),
162 m
.d
.comb
+= r_port
.en
.eq(self
.r_en
)
164 m
.d
.sync
+= consume
.eq(_incr(consume
, self
.depth
))
166 with m
.If(do_write
& ~do_read
):
167 m
.d
.sync
+= self
.level
.eq(self
.level
+ 1)
168 with m
.If(do_read
& ~do_write
):
169 m
.d
.sync
+= self
.level
.eq(self
.level
- 1)
171 if platform
== "formal":
172 # TODO: move this logic to SymbiYosys
173 with m
.If(Initial()):
175 Assume(produce
< self
.depth
),
176 Assume(consume
< self
.depth
),
178 with m
.If(produce
== consume
):
179 m
.d
.comb
+= Assume((self
.level
== 0) |
(self
.level
== self
.depth
))
180 with m
.If(produce
> consume
):
181 m
.d
.comb
+= Assume(self
.level
== (produce
- consume
))
182 with m
.If(produce
< consume
):
183 m
.d
.comb
+= Assume(self
.level
== (self
.depth
+ produce
- consume
))
186 Assert(produce
< self
.depth
),
187 Assert(consume
< self
.depth
),
189 with m
.If(produce
== consume
):
190 m
.d
.comb
+= Assert((self
.level
== 0) |
(self
.level
== self
.depth
))
191 with m
.If(produce
> consume
):
192 m
.d
.comb
+= Assert(self
.level
== (produce
- consume
))
193 with m
.If(produce
< consume
):
194 m
.d
.comb
+= Assert(self
.level
== (self
.depth
+ produce
- consume
))
199 class SyncFIFOBuffered(Elaboratable
, FIFOInterface
):
200 __doc__
= FIFOInterface
._doc
_template
.format(
202 Buffered synchronous first in, first out queue.
204 This queue's interface is identical to :class:`SyncFIFO` configured as ``fwft=True``, but it
205 does not use asynchronous memory reads, which are incompatible with FPGA block RAMs.
207 In exchange, the latency between an entry being written to an empty queue and that entry
208 becoming available on the output is increased by one cycle compared to :class:`SyncFIFO`.
215 r_data_valid
="Valid if ``r_rdy`` is asserted.",
218 Number of unread entries.
222 def __init__(self
, *, width
, depth
):
223 super().__init
__(width
=width
, depth
=depth
, fwft
=True)
225 self
.level
= Signal(range(depth
+ 1))
227 def elaborate(self
, platform
):
236 # Effectively, this queue treats the output register of the non-FWFT inner queue as
237 # an additional storage element.
238 m
.submodules
.unbuffered
= fifo
= SyncFIFO(width
=self
.width
, depth
=self
.depth
- 1,
242 fifo
.w_data
.eq(self
.w_data
),
243 fifo
.w_en
.eq(self
.w_en
),
244 self
.w_rdy
.eq(fifo
.w_rdy
),
248 self
.r_data
.eq(fifo
.r_data
),
249 fifo
.r_en
.eq(fifo
.r_rdy
& (~self
.r_rdy | self
.r_en
)),
251 with m
.If(fifo
.r_en
):
252 m
.d
.sync
+= self
.r_rdy
.eq(1)
253 with m
.Elif(self
.r_en
):
254 m
.d
.sync
+= self
.r_rdy
.eq(0)
257 self
.level
.eq(fifo
.level
+ self
.r_rdy
),
258 self
.w_level
.eq(self
.level
),
259 self
.r_level
.eq(self
.level
),
265 class AsyncFIFO(Elaboratable
, FIFOInterface
):
266 __doc__
= FIFOInterface
._doc
_template
.format(
268 Asynchronous first in, first out queue.
270 Read and write interfaces are accessed from different clock domains, which can be set when
271 constructing the FIFO.
273 :class:`AsyncFIFO` can be reset from the write clock domain. When the write domain reset is
274 asserted, the FIFO becomes empty. When the read domain is reset, data remains in the FIFO - the
275 read domain logic should correctly handle this case.
277 :class:`AsyncFIFO` only supports power of 2 depths. Unless ``exact_depth`` is specified,
278 the ``depth`` parameter is rounded up to the next power of 2.
290 r_data_valid
="Valid if ``r_rdy`` is asserted.",
293 Asserted while the FIFO is being reset by the write-domain reset (for at least one
294 read-domain clock cycle).
298 def __init__(self
, *, width
, depth
, r_domain
="read", w_domain
="write", exact_depth
=False):
301 depth_bits
= log2_int(depth
, need_pow2
=exact_depth
)
302 depth
= 1 << depth_bits
303 except ValueError as e
:
304 raise ValueError("AsyncFIFO only supports depths that are powers of 2; requested "
305 "exact depth {} is not"
306 .format(depth
)) from None
309 super().__init
__(width
=width
, depth
=depth
, fwft
=True)
311 self
.r_rst
= Signal()
312 self
._r
_domain
= r_domain
313 self
._w
_domain
= w_domain
314 self
._ctr
_bits
= depth_bits
+ 1
316 def elaborate(self
, platform
):
325 # The design of this queue is the "style #2" from Clifford E. Cummings' paper "Simulation
326 # and Synthesis Techniques for Asynchronous FIFO Design":
327 # http://www.sunburst-design.com/papers/CummingsSNUG2002SJ_FIFO1.pdf
329 do_write
= self
.w_rdy
& self
.w_en
330 do_read
= self
.r_rdy
& self
.r_en
332 # TODO: extract this pattern into lib.cdc.GrayCounter
333 produce_w_bin
= Signal(self
._ctr
_bits
)
334 produce_w_nxt
= Signal(self
._ctr
_bits
)
335 m
.d
.comb
+= produce_w_nxt
.eq(produce_w_bin
+ do_write
)
336 m
.d
[self
._w
_domain
] += produce_w_bin
.eq(produce_w_nxt
)
338 # Note: Both read-domain counters must be reset_less (see comments below)
339 consume_r_bin
= Signal(self
._ctr
_bits
, reset_less
=True)
340 consume_r_nxt
= Signal(self
._ctr
_bits
)
341 m
.d
.comb
+= consume_r_nxt
.eq(consume_r_bin
+ do_read
)
342 m
.d
[self
._r
_domain
] += consume_r_bin
.eq(consume_r_nxt
)
344 produce_w_gry
= Signal(self
._ctr
_bits
)
345 produce_r_gry
= Signal(self
._ctr
_bits
)
346 produce_enc
= m
.submodules
.produce_enc
= \
347 GrayEncoder(self
._ctr
_bits
)
348 produce_cdc
= m
.submodules
.produce_cdc
= \
349 FFSynchronizer(produce_w_gry
, produce_r_gry
, o_domain
=self
._r
_domain
)
350 m
.d
.comb
+= produce_enc
.i
.eq(produce_w_nxt
),
351 m
.d
[self
._w
_domain
] += produce_w_gry
.eq(produce_enc
.o
)
353 consume_r_gry
= Signal(self
._ctr
_bits
, reset_less
=True)
354 consume_w_gry
= Signal(self
._ctr
_bits
)
355 consume_enc
= m
.submodules
.consume_enc
= \
356 GrayEncoder(self
._ctr
_bits
)
357 consume_cdc
= m
.submodules
.consume_cdc
= \
358 FFSynchronizer(consume_r_gry
, consume_w_gry
, o_domain
=self
._w
_domain
)
359 m
.d
.comb
+= consume_enc
.i
.eq(consume_r_nxt
)
360 m
.d
[self
._r
_domain
] += consume_r_gry
.eq(consume_enc
.o
)
362 consume_w_bin
= Signal(self
._ctr
_bits
)
363 consume_dec
= m
.submodules
.consume_dec
= \
364 GrayDecoder(self
._ctr
_bits
)
365 m
.d
.comb
+= consume_dec
.i
.eq(consume_w_gry
),
366 m
.d
[self
._w
_domain
] += consume_w_bin
.eq(consume_dec
.o
)
368 produce_r_bin
= Signal(self
._ctr
_bits
)
369 produce_dec
= m
.submodules
.produce_dec
= \
370 GrayDecoder(self
._ctr
_bits
)
371 m
.d
.comb
+= produce_dec
.i
.eq(produce_r_gry
),
372 m
.d
[self
._r
_domain
] += produce_r_bin
.eq(produce_dec
.o
)
377 w_full
.eq((produce_w_gry
[-1] != consume_w_gry
[-1]) &
378 (produce_w_gry
[-2] != consume_w_gry
[-2]) &
379 (produce_w_gry
[:-2] == consume_w_gry
[:-2])),
380 r_empty
.eq(consume_r_gry
== produce_r_gry
),
383 m
.d
[self
._w
_domain
] += self
.w_level
.eq((produce_w_bin
- consume_w_bin
)[:self
._ctr
_bits
-1])
384 m
.d
[self
._r
_domain
] += self
.r_level
.eq((produce_r_bin
- consume_r_bin
)[:self
._ctr
_bits
-1])
386 storage
= Memory(width
=self
.width
, depth
=self
.depth
)
387 w_port
= m
.submodules
.w_port
= storage
.write_port(domain
=self
._w
_domain
)
388 r_port
= m
.submodules
.r_port
= storage
.read_port (domain
=self
._r
_domain
,
391 w_port
.addr
.eq(produce_w_bin
[:-1]),
392 w_port
.data
.eq(self
.w_data
),
393 w_port
.en
.eq(do_write
),
394 self
.w_rdy
.eq(~w_full
),
397 r_port
.addr
.eq(consume_r_nxt
[:-1]),
398 self
.r_data
.eq(r_port
.data
),
400 self
.r_rdy
.eq(~r_empty
),
403 # Reset handling to maintain FIFO and CDC invariants in the presence of a write-domain
405 # There is a CDC hazard associated with resetting an async FIFO - Gray code counters which
406 # are reset to 0 violate their Gray code invariant. One way to handle this is to ensure
407 # that both sides of the FIFO are asynchronously reset by the same signal. We adopt a
408 # slight variation on this approach - reset control rests entirely with the write domain.
409 # The write domain's reset signal is used to asynchronously reset the read domain's
410 # counters and force the FIFO to be empty when the write domain's reset is asserted.
411 # This requires the two read domain counters to be marked as "reset_less", as they are
412 # reset through another mechanism. See https://github.com/nmigen/nmigen/issues/181 for the
414 w_rst
= ResetSignal(domain
=self
._w
_domain
, allow_reset_less
=True)
417 # Async-set-sync-release synchronizer avoids CDC hazards
418 rst_cdc
= m
.submodules
.rst_cdc
= \
419 AsyncFFSynchronizer(w_rst
, r_rst
, domain
=self
._r
_domain
)
421 # Decode Gray code counter synchronized from write domain to overwrite binary
422 # counter in read domain.
423 rst_dec
= m
.submodules
.rst_dec
= \
424 GrayDecoder(self
._ctr
_bits
)
425 m
.d
.comb
+= rst_dec
.i
.eq(produce_r_gry
)
427 m
.d
.comb
+= r_empty
.eq(1)
428 m
.d
[self
._r
_domain
] += consume_r_gry
.eq(produce_r_gry
)
429 m
.d
[self
._r
_domain
] += consume_r_bin
.eq(rst_dec
.o
)
430 m
.d
[self
._r
_domain
] += self
.r_rst
.eq(1)
432 m
.d
[self
._r
_domain
] += self
.r_rst
.eq(0)
434 if platform
== "formal":
435 with m
.If(Initial()):
436 m
.d
.comb
+= Assume(produce_w_gry
== (produce_w_bin ^ produce_w_bin
[1:]))
437 m
.d
.comb
+= Assume(consume_r_gry
== (consume_r_bin ^ consume_r_bin
[1:]))
442 class AsyncFIFOBuffered(Elaboratable
, FIFOInterface
):
443 __doc__
= FIFOInterface
._doc
_template
.format(
445 Buffered asynchronous first in, first out queue.
447 Read and write interfaces are accessed from different clock domains, which can be set when
448 constructing the FIFO.
450 :class:`AsyncFIFOBuffered` only supports power of 2 plus one depths. Unless ``exact_depth``
451 is specified, the ``depth`` parameter is rounded up to the next power of 2 plus one.
452 (The output buffer acts as an additional queue element.)
454 This queue's interface is identical to :class:`AsyncFIFO`, but it has an additional register
455 on the output, improving timing in case of block RAM that has large clock-to-output delay.
457 In exchange, the latency between an entry being written to an empty queue and that entry
458 becoming available on the output is increased by one cycle compared to :class:`AsyncFIFO`.
470 r_data_valid
="Valid if ``r_rdy`` is asserted.",
473 Asserted while the FIFO is being reset by the write-domain reset (for at least one
474 read-domain clock cycle).
478 def __init__(self
, *, width
, depth
, r_domain
="read", w_domain
="write", exact_depth
=False):
481 depth_bits
= log2_int(max(0, depth
- 1), need_pow2
=exact_depth
)
482 depth
= (1 << depth_bits
) + 1
483 except ValueError as e
:
484 raise ValueError("AsyncFIFOBuffered only supports depths that are one higher "
485 "than powers of 2; requested exact depth {} is not"
486 .format(depth
)) from None
487 super().__init
__(width
=width
, depth
=depth
, fwft
=True)
489 self
.r_rst
= Signal()
490 self
._r
_domain
= r_domain
491 self
._w
_domain
= w_domain
493 def elaborate(self
, platform
):
502 m
.submodules
.unbuffered
= fifo
= AsyncFIFO(width
=self
.width
, depth
=self
.depth
- 1,
503 r_domain
=self
._r
_domain
, w_domain
=self
._w
_domain
)
506 fifo
.w_data
.eq(self
.w_data
),
507 self
.w_rdy
.eq(fifo
.w_rdy
),
508 fifo
.w_en
.eq(self
.w_en
),
509 self
.w_level
.eq(fifo
.w_level
),
512 with m
.If(self
.r_en | ~self
.r_rdy
):
513 m
.d
[self
._r
_domain
] += [
514 self
.r_data
.eq(fifo
.r_data
),
515 self
.r_rdy
.eq(fifo
.r_rdy
),
516 self
.r_rst
.eq(fifo
.r_rst
),
517 self
.r_level
.eq(fifo
.r_level
),