8f4e14237ca03596a69efc3e15550f3d785fc796
1 from migen
.fhdl
.structure
import *
2 from migen
.fhdl
.module
import Module
3 from migen
.fhdl
.specials
import Memory
4 from migen
.fhdl
.bitcontainer
import log2_int
5 from migen
.fhdl
.decorators
import ClockDomainsRenamer
6 from migen
.genlib
.cdc
import NoRetiming
, MultiReg
, GrayCounter
9 def _inc(signal
, modulo
):
10 if modulo
== 2**len(signal
):
11 return signal
.eq(signal
+ 1)
13 return If(signal
== (modulo
- 1),
22 Data written to the input interface (`din`, `we`, `writable`) is
23 buffered and can be read at the output interface (`dout`, `re`,
24 `readable`). The data entry written first to the input
25 also appears first on the output.
30 Bit width for the data.
39 There is space in the FIFO and `we` can be asserted to load new data.
41 Write enable signal to latch `din` into the FIFO. Does nothing if
42 `writable` is not asserted.
44 Output data. Only valid if `readable` is asserted.
46 Output data `dout` valid, FIFO not empty.
48 Acknowledge `dout`. If asserted, the next entry will be
49 available on the next cycle (if `readable` is high then).
51 def __init__(self
, width
, depth
):
53 self
.writable
= Signal() # not full
55 self
.readable
= Signal() # not empty
57 self
.din
= Signal(width
)
58 self
.dout
= Signal(width
)
62 class SyncFIFO(Module
, _FIFOInterface
):
63 """Synchronous FIFO (first in, first out)
65 Read and write interfaces are accessed from the same clock domain.
66 If different clock domains are needed, use :class:`AsyncFIFO`.
70 Number of unread entries.
72 Replaces the last entry written into the FIFO with `din`. Does nothing
73 if that entry has already been read (i.e. the FIFO is empty).
74 Assert in conjunction with `we`.
76 __doc__
= __doc__
.format(interface
=_FIFOInterface
.__doc
__)
78 def __init__(self
, width
, depth
, fwft
=True):
79 _FIFOInterface
.__init
__(self
, width
, depth
)
81 self
.level
= Signal(max=depth
+1)
82 self
.replace
= Signal()
86 produce
= Signal(max=depth
)
87 consume
= Signal(max=depth
)
88 storage
= Memory(self
.width
, depth
)
89 self
.specials
+= storage
91 wrport
= storage
.get_port(write_capable
=True)
92 self
.specials
+= wrport
95 wrport
.adr
.eq(produce
-1)
97 wrport
.adr
.eq(produce
)
99 wrport
.dat_w
.eq(self
.din
),
100 wrport
.we
.eq(self
.we
& (self
.writable | self
.replace
))
102 self
.sync
+= If(self
.we
& self
.writable
& ~self
.replace
,
103 _inc(produce
, depth
))
106 self
.comb
+= do_read
.eq(self
.readable
& self
.re
)
108 rdport
= storage
.get_port(async_read
=fwft
, has_re
=not fwft
)
109 self
.specials
+= rdport
111 rdport
.adr
.eq(consume
),
112 self
.dout
.eq(rdport
.dat_r
)
115 self
.comb
+= rdport
.re
.eq(do_read
)
116 self
.sync
+= If(do_read
, _inc(consume
, depth
))
119 If(self
.we
& self
.writable
& ~self
.replace
,
120 If(~do_read
, self
.level
.eq(self
.level
+ 1))
122 self
.level
.eq(self
.level
- 1)
125 self
.writable
.eq(self
.level
!= depth
),
126 self
.readable
.eq(self
.level
!= 0)
130 class SyncFIFOBuffered(Module
, _FIFOInterface
):
131 def __init__(self
, width
, depth
):
132 _FIFOInterface
.__init
__(self
, width
, depth
)
133 self
.submodules
.fifo
= fifo
= SyncFIFO(width
, depth
, False)
135 self
.writable
= fifo
.writable
138 self
.dout
= fifo
.dout
139 self
.level
= Signal(max=depth
+2)
143 self
.comb
+= fifo
.re
.eq(fifo
.readable
& (~self
.readable | self
.re
))
150 self
.comb
+= self
.level
.eq(fifo
.level
+ self
.readable
)
153 class AsyncFIFO(Module
, _FIFOInterface
):
154 """Asynchronous FIFO (first in, first out)
156 Read and write interfaces are accessed from different clock domains,
157 named `read` and `write`. Use `ClockDomainsRenamer` to rename to
162 __doc__
= __doc__
.format(interface
=_FIFOInterface
.__doc
__)
164 def __init__(self
, width
, depth
):
165 _FIFOInterface
.__init
__(self
, width
, depth
)
169 depth_bits
= log2_int(depth
, True)
171 produce
= ClockDomainsRenamer("write")(GrayCounter(depth_bits
+1))
172 consume
= ClockDomainsRenamer("read")(GrayCounter(depth_bits
+1))
173 self
.submodules
+= produce
, consume
175 produce
.ce
.eq(self
.writable
& self
.we
),
176 consume
.ce
.eq(self
.readable
& self
.re
)
179 produce_rdomain
= Signal(depth_bits
+1)
181 NoRetiming(produce
.q
),
182 MultiReg(produce
.q
, produce_rdomain
, "read")
184 consume_wdomain
= Signal(depth_bits
+1)
186 NoRetiming(consume
.q
),
187 MultiReg(consume
.q
, consume_wdomain
, "write")
190 self
.comb
+= self
.writable
.eq((produce
.q
[-1] == consume_wdomain
[-1])
191 |
(produce
.q
[-2] == consume_wdomain
[-2]))
194 self
.writable
.eq((produce
.q
[-1] == consume_wdomain
[-1])
195 |
(produce
.q
[-2] == consume_wdomain
[-2])
196 |
(produce
.q
[:-2] != consume_wdomain
[:-2]))
198 self
.comb
+= self
.readable
.eq(consume
.q
!= produce_rdomain
)
200 storage
= Memory(self
.width
, depth
)
201 self
.specials
+= storage
202 wrport
= storage
.get_port(write_capable
=True, clock_domain
="write")
203 self
.specials
+= wrport
205 wrport
.adr
.eq(produce
.q_binary
[:-1]),
206 wrport
.dat_w
.eq(self
.din
),
207 wrport
.we
.eq(produce
.ce
)
209 rdport
= storage
.get_port(clock_domain
="read")
210 self
.specials
+= rdport
212 rdport
.adr
.eq(consume
.q_next_binary
[:-1]),
213 self
.dout
.eq(rdport
.dat_r
)