La respuesta simple es que no lo hacen solos. El sincronizador no está ahí para garantizar que los datos se transmitan, sino para garantizar que no termines con señales metaestables que alimenten muchas otras señales y causen problemas. El segundo FF como muestra el diagrama captura la primera salida de FF metaestable y evita que se propague aún más a través del diseño.
Hay varios tipos de señales, y la forma en que incluya sincronizadores depende de la señal de la que esté hablando. Pero veamos un par de tipos comunes:
Señales de activación - o cualquier señal que sea básicamente un impulso que debe iniciar algo más en funcionamiento. Por lo general, estos no contienen datos, y todo lo que le interesa es que haya, por ejemplo, un borde ascendente para comenzar a que algo vaya en otro dominio de reloj. Para que estos se crucen, necesitaría un sincronizador (esencialmente haciendo lo que se muestra en su diagrama), pero necesita un poco más.
La opción más simple es extender el pulso: esencialmente se asegura de que el pulso de entrada sea más de 1 período de reloj del reloj de destino (debe ser más largo que 1 ciclo por al menos el mayor tiempo de configuración y retención para el registro de destino) . Por ejemplo, si va de un reloj de 20MHz a un reloj de 15MHz, se asegurará de que su pulso sea de dos ciclos de reloj en la entrada, lo que garantizaría que se presente en el reloj de destino y no se pierda. Esto también responde a su pregunta sobre cómo se garantiza que la señal se transmita. Si el pulso es más ancho que un período de reloj de destino, significa que si se metaestable en el primer borde del reloj y termina siendo visto como un 0, entonces en el segundo borde del reloj definitivamente capturará el pulso.
Debido a que con este tipo de señal solo le interesa que el pulso se haya transmitido, no importa si la señal de salida termina con dos ciclos de reloj altos algunas veces y solo un ciclo el resto. Si necesita asegurarse de que sea un pulso de ciclo único, puede crear una instancia de un circuito detector de borde simple.
Buses de control , o posiblemente tipos de buses de datos. Podría decirse que son más difíciles porque si tiene un flujo de datos de varios bits que necesita estar sincronizado. En este caso, lo que haría es implementar algo llamado "apretón de manos". Básicamente carga sus datos en el reloj de origen y los mantiene. Luego, envía una señal de solicitud (como en 1) a través de un sincronizador. Una vez que la señal de solicitud está cruzada, sabe que el bus de datos también se estabilizará en el dominio de destino. Luego puede registrarlo en un banco de registro en el destino. El destino luego envía un pulso de confirmación nuevamente para informar a la fuente que puede cargar la siguiente palabra.
Usaría este tipo de bus si necesitara enviar una palabra de control al reloj de destino para el que necesita saber que llegó allí antes de enviar otro (por ejemplo, si envía un comando para hacer algo).
Buses de datos : para los datos donde tiene una fuente que escupe datos continuamente o en ráfagas, podría decirse que es mejor usar un FIFO que sincronizadores. El FIFO usa una memoria de reloj doble para guardar los datos, junto con contadores para realizar un seguimiento de la cantidad de datos que hay en el FIFO. Escribe los datos en el FIFO cuando hay espacio y luego incrementa la dirección de escritura. Esta dirección generalmente se codifica en un esquema de "codificación gris" que garantiza que cada incremento en la dirección cause solo unobit en el bus de direcciones para cambiar (lo que significa que no necesita sincronizar varios bits). Esta dirección se transfiere al dominio de destino (a través de una de sus cadenas de sincronizador), donde se compara con la dirección de lectura. Si hay datos en el FIFO, se pueden leer de la memoria utilizando el puerto del reloj de destino. La dirección de lectura tiene un código gris similar y se envía de vuelta a la fuente a través de otro sincronizador para que el puerto de escritura pueda calcular si hay espacio en la FIFO.
Señales de reinicio : por lo general, usan una versión modificada del sincronizador en lo que se conoce como "Afirmación asincrónica, Desassert sincrónico". En esta versión modificada, la entrada de datos al primer flip flop está vinculada a GND y, en cambio, la señal de reinicio entrante se conecta a las señales preestablecidas asincrónicas de cada flip-flop en el sincronizador. Esto da como resultado una señal de salida que es completamente asíncrona cuando sube, pero la cadena sincronizadora asegura que baja sincrónicamente con el reloj de destino marcando ceros en la cadena de registro.
Este tipo de sincronizador es terrible para los datos y el control, pero es perfecto para restablecer las señales. Si toda la lógica de destino alimenta la salida de esta cadena a las entradas de reinicio asíncrono de cualquier registro en el dominio, entonces hay poca preocupación por la metaestabilidad en el proceso de aserción (aunque sea asíncrono) ya que todos los registros se ven forzados a un estado conocido. Luego, cuando la señal de reinicio se desasiste en el dominio de origen, se desasocia sincrónicamente en el dominio de destino, lo que significa que todos los registros salen del reinicio en el mismo ciclo de reloj (en lugar de +/- 1 ciclo si fue un desassert asíncrono).
Como puede ver en lo anterior, es mucho más complejo hacer un cruce de dominio de reloj que simplemente pegar un sincronizador de 2 flip-flop en la señal. El método exacto utilizado depende de la aplicación.