lib.fifo: register GrayEncoder output before CDC.
Without this register, static hazards in the encoder could cause multiple encoder output bits to toggle, which would be incorrectly sampled by the 2FF synchronizer. Reported by @Wren6991.
This commit is contained in:
parent
e93bf4bf4b
commit
4027317835
|
@ -297,29 +297,37 @@ class AsyncFIFO(FIFOInterface):
|
||||||
|
|
||||||
m = Module()
|
m = Module()
|
||||||
|
|
||||||
|
do_write = self.writable & self.we
|
||||||
|
do_read = self.readable & self.re
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
m.d.comb += produce_w_nxt.eq(produce_w_bin + do_write)
|
||||||
|
m.d.write += 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)
|
||||||
|
|
||||||
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, odomain="read")
|
MultiReg(produce_w_gry, produce_r_gry, odomain="read")
|
||||||
m.d.comb += [
|
m.d.comb += produce_enc.i.eq(produce_w_nxt),
|
||||||
produce_enc.i.eq(produce_w_bin),
|
m.d.write += produce_w_gry.eq(produce_enc.o)
|
||||||
produce_w_gry.eq(produce_enc.o),
|
|
||||||
]
|
|
||||||
|
|
||||||
consume_r_bin = Signal(self._ctr_bits)
|
|
||||||
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, odomain="write")
|
MultiReg(consume_r_gry, consume_w_gry, odomain="write")
|
||||||
m.d.comb += [
|
m.d.comb += consume_enc.i.eq(consume_r_nxt)
|
||||||
consume_enc.i.eq(consume_r_bin),
|
m.d.read += consume_r_gry.eq(consume_enc.o)
|
||||||
consume_r_gry.eq(consume_enc.o),
|
|
||||||
]
|
|
||||||
|
|
||||||
m.d.comb += [
|
m.d.comb += [
|
||||||
self.writable.eq(
|
self.writable.eq(
|
||||||
|
@ -329,11 +337,6 @@ class AsyncFIFO(FIFOInterface):
|
||||||
self.readable.eq(consume_r_gry != produce_r_gry)
|
self.readable.eq(consume_r_gry != produce_r_gry)
|
||||||
]
|
]
|
||||||
|
|
||||||
do_write = self.writable & self.we
|
|
||||||
do_read = self.readable & self.re
|
|
||||||
m.d.write += produce_w_bin.eq(produce_w_bin + do_write)
|
|
||||||
m.d.read += consume_r_bin.eq(consume_r_bin + do_read)
|
|
||||||
|
|
||||||
storage = Memory(self.width, self.depth)
|
storage = Memory(self.width, self.depth)
|
||||||
wrport = m.submodules.wrport = storage.write_port(domain="write")
|
wrport = m.submodules.wrport = storage.write_port(domain="write")
|
||||||
rdport = m.submodules.rdport = storage.read_port (domain="read")
|
rdport = m.submodules.rdport = storage.read_port (domain="read")
|
||||||
|
@ -347,6 +350,14 @@ class AsyncFIFO(FIFOInterface):
|
||||||
self.dout.eq(rdport.data),
|
self.dout.eq(rdport.data),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if platform == "formal":
|
||||||
|
# TODO: move this logic elsewhere
|
||||||
|
initstate = Signal()
|
||||||
|
m.submodules += Instance("$initstate", o_Y=initstate)
|
||||||
|
with m.If(initstate):
|
||||||
|
m.d.comb += Assume(produce_w_gry == (produce_w_bin ^ produce_w_bin[1:]))
|
||||||
|
m.d.comb += Assume(consume_r_gry == (consume_r_bin ^ consume_r_bin[1:]))
|
||||||
|
|
||||||
return m
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue