parent
da4b810fe1
commit
bdb70ad45f
|
@ -291,21 +291,29 @@ class AsyncFIFO(Elaboratable, FIFOInterface):
|
||||||
description="""
|
description="""
|
||||||
Asynchronous first in, first out queue.
|
Asynchronous first in, first out queue.
|
||||||
|
|
||||||
Read and write interfaces are accessed from different clock domains, called ``read``
|
Read and write interfaces are accessed from different clock domains, which can be set when
|
||||||
and ``write``; use :class:`DomainRenamer` to rename them as appropriate for the design.
|
constructing the FIFO.
|
||||||
""".strip(),
|
""".strip(),
|
||||||
parameters="""
|
parameters="""
|
||||||
|
r_domain : str
|
||||||
|
Read clock domain.
|
||||||
|
w_domain : str
|
||||||
|
Write clock domain.
|
||||||
|
""".strip(),
|
||||||
|
attributes="""
|
||||||
fwft : bool
|
fwft : bool
|
||||||
Always set.
|
Always set.
|
||||||
""".strip(),
|
""".strip(),
|
||||||
attributes="",
|
|
||||||
r_data_valid="Valid if ``r_rdy`` is asserted.",
|
r_data_valid="Valid if ``r_rdy`` is asserted.",
|
||||||
r_attributes="",
|
r_attributes="",
|
||||||
w_attributes="")
|
w_attributes="")
|
||||||
|
|
||||||
def __init__(self, width, depth):
|
def __init__(self, width, depth, *, r_domain="read", w_domain="write"):
|
||||||
super().__init__(width, depth, fwft=True)
|
super().__init__(width, depth, fwft=True)
|
||||||
|
|
||||||
|
self._r_domain = r_domain
|
||||||
|
self._w_domain = w_domain
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._ctr_bits = log2_int(depth, need_pow2=True) + 1
|
self._ctr_bits = log2_int(depth, need_pow2=True) + 1
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
|
@ -324,31 +332,31 @@ class AsyncFIFO(Elaboratable, FIFOInterface):
|
||||||
# TODO: extract this pattern into lib.cdc.GrayCounter
|
# TODO: extract this pattern into lib.cdc.GrayCounter
|
||||||
produce_w_bin = Signal(self._ctr_bits)
|
produce_w_bin = Signal(self._ctr_bits)
|
||||||
produce_w_nxt = Signal(self._ctr_bits)
|
produce_w_nxt = Signal(self._ctr_bits)
|
||||||
m.d.comb += produce_w_nxt.eq(produce_w_bin + do_write)
|
m.d.comb += produce_w_nxt.eq(produce_w_bin + do_write)
|
||||||
m.d.write += produce_w_bin.eq(produce_w_nxt)
|
m.d[self._w_domain] += produce_w_bin.eq(produce_w_nxt)
|
||||||
|
|
||||||
consume_r_bin = Signal(self._ctr_bits)
|
consume_r_bin = Signal(self._ctr_bits)
|
||||||
consume_r_nxt = Signal(self._ctr_bits)
|
consume_r_nxt = Signal(self._ctr_bits)
|
||||||
m.d.comb += consume_r_nxt.eq(consume_r_bin + do_read)
|
m.d.comb += consume_r_nxt.eq(consume_r_bin + do_read)
|
||||||
m.d.read += consume_r_bin.eq(consume_r_nxt)
|
m.d[self._r_domain] += consume_r_bin.eq(consume_r_nxt)
|
||||||
|
|
||||||
produce_w_gry = Signal(self._ctr_bits)
|
produce_w_gry = Signal(self._ctr_bits)
|
||||||
produce_r_gry = Signal(self._ctr_bits)
|
produce_r_gry = Signal(self._ctr_bits)
|
||||||
produce_enc = m.submodules.produce_enc = \
|
produce_enc = m.submodules.produce_enc = \
|
||||||
GrayEncoder(self._ctr_bits)
|
GrayEncoder(self._ctr_bits)
|
||||||
produce_cdc = m.submodules.produce_cdc = \
|
produce_cdc = m.submodules.produce_cdc = \
|
||||||
MultiReg(produce_w_gry, produce_r_gry, o_domain="read")
|
MultiReg(produce_w_gry, produce_r_gry, o_domain=self._r_domain)
|
||||||
m.d.comb += produce_enc.i.eq(produce_w_nxt),
|
m.d.comb += produce_enc.i.eq(produce_w_nxt),
|
||||||
m.d.write += produce_w_gry.eq(produce_enc.o)
|
m.d[self._w_domain] += produce_w_gry.eq(produce_enc.o)
|
||||||
|
|
||||||
consume_r_gry = Signal(self._ctr_bits)
|
consume_r_gry = Signal(self._ctr_bits)
|
||||||
consume_w_gry = Signal(self._ctr_bits)
|
consume_w_gry = Signal(self._ctr_bits)
|
||||||
consume_enc = m.submodules.consume_enc = \
|
consume_enc = m.submodules.consume_enc = \
|
||||||
GrayEncoder(self._ctr_bits)
|
GrayEncoder(self._ctr_bits)
|
||||||
consume_cdc = m.submodules.consume_cdc = \
|
consume_cdc = m.submodules.consume_cdc = \
|
||||||
MultiReg(consume_r_gry, consume_w_gry, o_domain="write")
|
MultiReg(consume_r_gry, consume_w_gry, o_domain=self._w_domain)
|
||||||
m.d.comb += consume_enc.i.eq(consume_r_nxt)
|
m.d.comb += consume_enc.i.eq(consume_r_nxt)
|
||||||
m.d.read += consume_r_gry.eq(consume_enc.o)
|
m.d[self._r_domain] += consume_r_gry.eq(consume_enc.o)
|
||||||
|
|
||||||
m.d.comb += [
|
m.d.comb += [
|
||||||
self.w_rdy.eq(
|
self.w_rdy.eq(
|
||||||
|
@ -359,8 +367,8 @@ class AsyncFIFO(Elaboratable, FIFOInterface):
|
||||||
]
|
]
|
||||||
|
|
||||||
storage = Memory(self.width, self.depth)
|
storage = Memory(self.width, self.depth)
|
||||||
w_port = m.submodules.w_port = storage.write_port(domain="write")
|
w_port = m.submodules.w_port = storage.write_port(domain=self._w_domain)
|
||||||
r_port = m.submodules.r_port = storage.read_port (domain="read")
|
r_port = m.submodules.r_port = storage.read_port (domain=self._r_domain)
|
||||||
m.d.comb += [
|
m.d.comb += [
|
||||||
w_port.addr.eq(produce_w_bin[:-1]),
|
w_port.addr.eq(produce_w_bin[:-1]),
|
||||||
w_port.data.eq(self.w_data),
|
w_port.data.eq(self.w_data),
|
||||||
|
@ -384,6 +392,9 @@ class AsyncFIFOBuffered(Elaboratable, FIFOInterface):
|
||||||
description="""
|
description="""
|
||||||
Buffered asynchronous first in, first out queue.
|
Buffered asynchronous first in, first out queue.
|
||||||
|
|
||||||
|
Read and write interfaces are accessed from different clock domains, which can be set when
|
||||||
|
constructing the FIFO.
|
||||||
|
|
||||||
This queue's interface is identical to :class:`AsyncFIFO`, but it has an additional register
|
This queue's interface is identical to :class:`AsyncFIFO`, but it has an additional register
|
||||||
on the output, improving timing in case of block RAM that has large clock-to-output delay.
|
on the output, improving timing in case of block RAM that has large clock-to-output delay.
|
||||||
|
|
||||||
|
@ -391,20 +402,29 @@ class AsyncFIFOBuffered(Elaboratable, FIFOInterface):
|
||||||
becoming available on the output is increased to one cycle.
|
becoming available on the output is increased to one cycle.
|
||||||
""".strip(),
|
""".strip(),
|
||||||
parameters="""
|
parameters="""
|
||||||
|
r_domain : str
|
||||||
|
Read clock domain.
|
||||||
|
w_domain : str
|
||||||
|
Write clock domain.
|
||||||
|
""".strip(),
|
||||||
|
attributes="""
|
||||||
fwft : bool
|
fwft : bool
|
||||||
Always set.
|
Always set.
|
||||||
""".strip(),
|
""".strip(),
|
||||||
attributes="",
|
|
||||||
r_data_valid="Valid if ``r_rdy`` is asserted.",
|
r_data_valid="Valid if ``r_rdy`` is asserted.",
|
||||||
r_attributes="",
|
r_attributes="",
|
||||||
w_attributes="")
|
w_attributes="")
|
||||||
|
|
||||||
def __init__(self, width, depth):
|
def __init__(self, width, depth, *, r_domain="read", w_domain="write"):
|
||||||
super().__init__(width, depth, fwft=True)
|
super().__init__(width, depth, fwft=True)
|
||||||
|
|
||||||
|
self._r_domain = r_domain
|
||||||
|
self._w_domain = w_domain
|
||||||
|
|
||||||
def elaborate(self, platform):
|
def elaborate(self, platform):
|
||||||
m = Module()
|
m = Module()
|
||||||
m.submodules.unbuffered = fifo = AsyncFIFO(self.width, self.depth - 1)
|
m.submodules.unbuffered = fifo = AsyncFIFO(self.width, self.depth - 1,
|
||||||
|
r_domain=self._r_domain, w_domain=self._w_domain)
|
||||||
|
|
||||||
m.d.comb += [
|
m.d.comb += [
|
||||||
fifo.w_data.eq(self.w_data),
|
fifo.w_data.eq(self.w_data),
|
||||||
|
@ -413,11 +433,12 @@ class AsyncFIFOBuffered(Elaboratable, FIFOInterface):
|
||||||
]
|
]
|
||||||
|
|
||||||
with m.If(self.r_en | ~self.r_rdy):
|
with m.If(self.r_en | ~self.r_rdy):
|
||||||
m.d.read += [
|
m.d[self._r_domain] += [
|
||||||
self.r_data.eq(fifo.r_data),
|
self.r_data.eq(fifo.r_data),
|
||||||
self.r_rdy.eq(fifo.r_rdy)
|
self.r_rdy.eq(fifo.r_rdy),
|
||||||
]
|
]
|
||||||
m.d.comb += \
|
m.d.comb += [
|
||||||
fifo.r_en.eq(1)
|
fifo.r_en.eq(1)
|
||||||
|
]
|
||||||
|
|
||||||
return m
|
return m
|
||||||
|
|
Loading…
Reference in a new issue