migen/genlib/cdc: fix BusSynchronizer

ping/pong token can be lost when:
- source clock domain starts before destination clock domain.
- a clock domain stops.

This fix add a timeout to detect such situation and create another token.
This commit is contained in:
Florent Kermarrec 2015-09-17 23:16:03 +02:00 committed by Sebastien Bourdeauducq
parent 07efe9d7b1
commit 210ba91d58
1 changed files with 5 additions and 2 deletions

View File

@ -2,6 +2,7 @@ from migen.fhdl.std import *
from migen.fhdl.bitcontainer import value_bits_sign from migen.fhdl.bitcontainer import value_bits_sign
from migen.fhdl.specials import Special from migen.fhdl.specials import Special
from migen.fhdl.tools import list_signals from migen.fhdl.tools import list_signals
from migen.genlib.misc import WaitTimer
class NoRetiming(Special): class NoRetiming(Special):
@ -88,7 +89,7 @@ class BusSynchronizer(Module):
Ensures that all the bits form a single word that was present Ensures that all the bits form a single word that was present
synchronously in the input clock domain (unlike direct use of synchronously in the input clock domain (unlike direct use of
``MultiReg``).""" ``MultiReg``)."""
def __init__(self, width, idomain, odomain): def __init__(self, width, idomain, odomain, timeout=128):
self.i = Signal(width) self.i = Signal(width)
self.o = Signal(width) self.o = Signal(width)
@ -102,8 +103,10 @@ class BusSynchronizer(Module):
sync_i += starter.eq(0) sync_i += starter.eq(0)
self.submodules._ping = PulseSynchronizer(idomain, odomain) self.submodules._ping = PulseSynchronizer(idomain, odomain)
self.submodules._pong = PulseSynchronizer(odomain, idomain) self.submodules._pong = PulseSynchronizer(odomain, idomain)
self.submodules._timeout = WaitTimer(timeout)
self.comb += [ self.comb += [
self._ping.i.eq(starter | self._pong.o), self._timeout.wait.eq(~self._ping.i),
self._ping.i.eq(starter | self._pong.o | self._timeout.done),
self._pong.i.eq(self._ping.i) self._pong.i.eq(self._ping.i)
] ]