Die einfache Antwort ist, dass sie nicht alleine sind. Der Synchronisierer ist nicht dazu da, um sicherzustellen, dass die Daten übertragen werden, aber um sicherzustellen, dass Sie keine metastabilen Signale erhalten, die viele andere Signale speisen und Probleme verursachen. Das zweite FF, wie das Diagramm zeigt, fängt den metastabilen ersten FF-Ausgang ab und verhindert, dass er sich weiter durch das Design ausbreitet.
Es gibt verschiedene Arten von Signalen, und wie Sie Synchronisierer einschließen, hängt davon ab, über welches Signal Sie sprechen. Aber schauen wir uns ein paar gängige Typen an:
Triggersignale - oder jedes Signal, das im Grunde ein Impuls ist, der etwas anderes zum Laufen bringen muss. Diese enthalten im Allgemeinen keine Daten, und alles, was Sie interessiert, ist, dass es beispielsweise eine steigende Flanke gibt, um etwas in einer anderen Taktdomäne in Gang zu setzen. Um diese zu überqueren, benötigen Sie einen Synchronisierer (im Wesentlichen das, was in Ihrem Diagramm gezeigt wird), aber Sie benötigen ein bisschen mehr.
Die einfachste Möglichkeit besteht darin, den Impuls zu verlängern. Im Wesentlichen stellen Sie sicher, dass der Eingangsimpuls mehr als 1 Taktperioden des Zieltakts beträgt (er sollte länger als 1 Zyklus sein, mindestens um die größere der Einrichtungs- und Haltezeiten für das Zielregister). . Wenn Sie beispielsweise von einem 20-MHz-Takt zu einem 15-MHz-Takt wechseln, stellen Sie sicher, dass Ihr Impuls zwei Taktzyklen am Eingang beträgt, um sicherzustellen, dass er dem Zieltakt angezeigt wird und nicht verloren geht. Dies beantwortet auch Ihre Frage, wie das Signal garantiert übertragen wird. Wenn der Impuls breiter als eine Zieltaktperiode ist, bedeutet dies, dass er den Impuls definitiv fängt, wenn er bei der ersten Taktflanke metastabil wird und als 0 angesehen wird.
Da Sie bei dieser Art von Signal nur daran interessiert sind, dass der Impuls übertragen wurde, spielt es keine Rolle, ob das Ausgangssignal manchmal zwei Taktzyklen hoch und den Rest nur einen Zyklus hat. Wenn Sie sicherstellen müssen, dass es sich um einen Einzelzyklusimpuls handelt, können Sie eine einfache Flankendetektorschaltung instanziieren.
Steuerbusse - oder möglicherweise Arten von Datenbussen. Diese sind wohl schwieriger, denn wenn Sie einen Multi-Bit-Datenstrom haben, der synchronisiert bleiben muss. In diesem Fall würden Sie etwas implementieren, das als "Handshaking" bezeichnet wird. Grundsätzlich laden Sie Ihre Daten auf die Quellentaktung und halten sie. Dann senden Sie ein Anforderungssignal (wie in 1) über einen Synchronisierer. Sobald das Anforderungssignal vorbei ist, wissen Sie, dass der Datenbus auch in der Zieldomäne stabilisiert wird. Sie können es dann in eine Registerbank im Ziel stempeln. Das Ziel sendet dann erneut einen Bestätigungsimpuls zurück, um die Quelle darüber zu informieren, dass es das nächste Wort laden kann.
Sie würden diese Art von Bus verwenden, wenn Sie ein Steuerwort an die Zieluhr senden müssen, für die Sie wissen müssen, dass es dort angekommen ist, bevor Sie einen anderen senden (z. B. wenn Sie einen Befehl senden, um etwas zu tun).
Datenbusse - Für Daten, bei denen Sie eine Quelle haben, die Daten kontinuierlich oder in Bursts ausspuckt, ist es wahrscheinlich besser, einen FIFO zu verwenden als Synchronisierer. Das FIFO verwendet einen Dual-Clock-Speicher zum Speichern der Daten sowie Zähler, um zu verfolgen, wie viele Daten sich im FIFO befinden. Sie schreiben die Daten in den FIFO, wenn Platz vorhanden ist, und erhöhen dann die Schreibadresse. Diese Adresse wird dann typischerweise in ein "Gray Coding" -Schema codiert, das sicherstellt, dass jedes Adressinkrement nur eine verursachtBit im zu ändernden Adressbus (dh Sie müssen nicht mehrere Bits synchronisieren). Diese Adresse wird dann an die Zieldomäne (über eine Ihrer Synchronisierketten) übertragen, wo sie mit der gelesenen Adresse verglichen wird. Befinden sich Daten im FIFO, können diese über den Zieltaktport aus dem Speicher ausgelesen werden. Die Leseadresse ist ähnlich grau codiert und wird über einen anderen Synchronisierer an die Quelle zurückgesendet, damit der Schreibport berechnen kann, ob im FIFO Platz vorhanden ist.
Signale zurücksetzen - Diese verwenden normalerweise eine modifizierte Version des Synchronisierers in "Asynchronous Assert, Synchronous Deassert". In dieser modifizierten Version ist der Dateneingang zum ersten Flipflop mit GND verbunden, und stattdessen wird das eingehende Rücksetzsignal mit asynchronen voreingestellten Signalen jedes Flipflops im Synchronisierer verbunden. Dies führt zu einem Ausgangssignal, das vollständig asynchron ist, wenn es hoch geht, aber die Synchronisierkette stellt sicher, dass es synchron mit dem Zieltakt niedrig geht, indem es durch Nullen in der Registerkette taktet.
Diese Art von Synchronisierer ist für Daten und Steuerung schrecklich, aber perfekt zum Zurücksetzen von Signalen geeignet. Wenn die gesamte Ziellogik den Ausgang dieser Kette in die asynchronen Rücksetzeingänge eines Registers in der Domäne einspeist, besteht wenig Bedenken hinsichtlich der Metastabilität beim Aktivieren (obwohl es asynchron ist), da alle Register in einen bekannten Zustand gezwungen werden. Wenn dann das Rücksetzsignal in der Quelldomäne deaktiviert wird, wird es in der Zieldomäne synchron deaktiviert, was bedeutet, dass alle Register im selben Taktzyklus nicht mehr zurückgesetzt werden (anstatt +/- 1 Zyklus, wenn es asynchron deaktiviert wurde).
Wie Sie oben sehen können, ist es viel komplexer, eine Taktdomänenkreuzung durchzuführen, als nur einen 2-Flip-Flop-Synchronisierer auf das Signal zu kleben. Die genaue Methode hängt von der Anwendung ab.