From 190d6e38b241a4066e6afb0889b1fcfd8337fbcc Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 12 Sep 2019 20:01:28 +0000 Subject: [PATCH] lib.fifo: adjust for new CDC primitive conventions. Fixes #97. --- nmigen/lib/fifo.py | 65 ++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/nmigen/lib/fifo.py b/nmigen/lib/fifo.py index cb847de..fc9e32d 100644 --- a/nmigen/lib/fifo.py +++ b/nmigen/lib/fifo.py @@ -291,21 +291,29 @@ class AsyncFIFO(Elaboratable, FIFOInterface): description=""" Asynchronous first in, first out queue. - Read and write interfaces are accessed from different clock domains, called ``read`` - and ``write``; use :class:`DomainRenamer` to rename them as appropriate for the design. + Read and write interfaces are accessed from different clock domains, which can be set when + constructing the FIFO. """.strip(), parameters=""" + r_domain : str + Read clock domain. + w_domain : str + Write clock domain. + """.strip(), + attributes=""" fwft : bool Always set. """.strip(), - attributes="", r_data_valid="Valid if ``r_rdy`` is asserted.", r_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) + self._r_domain = r_domain + self._w_domain = w_domain + try: self._ctr_bits = log2_int(depth, need_pow2=True) + 1 except ValueError as e: @@ -324,31 +332,31 @@ class AsyncFIFO(Elaboratable, FIFOInterface): # TODO: extract this pattern into lib.cdc.GrayCounter produce_w_bin = 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.write += produce_w_bin.eq(produce_w_nxt) + m.d.comb += produce_w_nxt.eq(produce_w_bin + do_write) + m.d[self._w_domain] += produce_w_bin.eq(produce_w_nxt) consume_r_bin = 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.read += consume_r_bin.eq(consume_r_nxt) + m.d.comb += consume_r_nxt.eq(consume_r_bin + do_read) + m.d[self._r_domain] += consume_r_bin.eq(consume_r_nxt) produce_w_gry = Signal(self._ctr_bits) produce_r_gry = Signal(self._ctr_bits) produce_enc = m.submodules.produce_enc = \ GrayEncoder(self._ctr_bits) produce_cdc = m.submodules.produce_cdc = \ - MultiReg(produce_w_gry, produce_r_gry, o_domain="read") - m.d.comb += produce_enc.i.eq(produce_w_nxt), - m.d.write += produce_w_gry.eq(produce_enc.o) + MultiReg(produce_w_gry, produce_r_gry, o_domain=self._r_domain) + m.d.comb += produce_enc.i.eq(produce_w_nxt), + m.d[self._w_domain] += produce_w_gry.eq(produce_enc.o) consume_r_gry = Signal(self._ctr_bits) consume_w_gry = Signal(self._ctr_bits) consume_enc = m.submodules.consume_enc = \ GrayEncoder(self._ctr_bits) consume_cdc = m.submodules.consume_cdc = \ - MultiReg(consume_r_gry, consume_w_gry, o_domain="write") - m.d.comb += consume_enc.i.eq(consume_r_nxt) - m.d.read += consume_r_gry.eq(consume_enc.o) + MultiReg(consume_r_gry, consume_w_gry, o_domain=self._w_domain) + m.d.comb += consume_enc.i.eq(consume_r_nxt) + m.d[self._r_domain] += consume_r_gry.eq(consume_enc.o) m.d.comb += [ self.w_rdy.eq( @@ -359,8 +367,8 @@ class AsyncFIFO(Elaboratable, FIFOInterface): ] storage = Memory(self.width, self.depth) - w_port = m.submodules.w_port = storage.write_port(domain="write") - r_port = m.submodules.r_port = storage.read_port (domain="read") + w_port = m.submodules.w_port = storage.write_port(domain=self._w_domain) + r_port = m.submodules.r_port = storage.read_port (domain=self._r_domain) m.d.comb += [ w_port.addr.eq(produce_w_bin[:-1]), w_port.data.eq(self.w_data), @@ -384,6 +392,9 @@ class AsyncFIFOBuffered(Elaboratable, FIFOInterface): description=""" 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 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. """.strip(), parameters=""" + r_domain : str + Read clock domain. + w_domain : str + Write clock domain. + """.strip(), + attributes=""" fwft : bool Always set. """.strip(), - attributes="", r_data_valid="Valid if ``r_rdy`` is asserted.", r_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) + self._r_domain = r_domain + self._w_domain = w_domain + def elaborate(self, platform): 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 += [ fifo.w_data.eq(self.w_data), @@ -413,11 +433,12 @@ class AsyncFIFOBuffered(Elaboratable, FIFOInterface): ] 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_rdy.eq(fifo.r_rdy) + self.r_rdy.eq(fifo.r_rdy), ] - m.d.comb += \ + m.d.comb += [ fifo.r_en.eq(1) + ] return m -- 2.30.2