el dominio del reloj de código gris cruza FIFO de rápido a lento

Estoy tratando de entender cómo se implementan los FIFO de cruce de reloj, y la respuesta habitual que veo es convertir los punteros de dirección de lectura/escritura en código gris y luego pasar a través de los circuitos sincronizadores al dominio del reloj de cada uno para determinar si hay datos contenidos en el FIFO. La idea de usar el código gris es que el otro dominio del reloj pueda detectar la metaestabilidad en el otro extremo por el hecho de que solo debe cambiar un bit por incremento de dirección... y puede ignorar con seguridad el puntero de la dirección hasta que parezca válido.

¿Qué pasa con el escenario en el que el dominio del reloj de escritura es mucho más rápido que el dominio del reloj lento? Si el puntero de dirección de escritura puede incrementarse muchas veces por ciclo de reloj de lectura, en algún momento habrá más de 1 bit invertido en el valor del código gris, y eso no sería necesariamente un error. ¿Cómo se suele manejar esta situación?

Sé que hay una pregunta similar en SE, pero la respuesta parece mostrar un ejemplo de que el reloj de escritura es solo 2 veces más rápido que el reloj de lectura, por lo que tal vez esta situación nunca se experimente.

Respuestas (1)

En un FIFO asíncrono, un dominio de reloj está asociado con el puerto de escritura y el puntero "principal" (la siguiente dirección de escritura) se mantiene en ese dominio de reloj. De manera similar, el otro dominio de reloj está asociado con el puerto de lectura y el puntero de "cola" se mantiene allí.

El problema es que ambos dominios de reloj deben poder realizar un seguimiento del número de palabras en el FIFO, y la forma de hacerlo es restar el valor del puntero de cola del valor del puntero de cabeza, módulo el tamaño de el carnero. Por lo tanto, cada puntero se codifica como código Gray, se transfiere al otro dominio de reloj y se vuelve a convertir a binario.

No importa si ocurre más de una escritura durante un período de reloj de lectura, o viceversa. El punto es que, con la codificación de código Gray, solo cambia un bit entre cualquier par de valores. Si un reloj detecta una transición en el otro dominio de reloj, como máximo solo un bit puede ser metaestable y la ambigüedad está entre dos estados adyacentes del contador.

En otras palabras, cada lado ve una secuencia de valores que aumenta monótonamente desde el otro lado, incluso si se omiten algunos valores y, lo que es más importante, incluso si se produce metaestabilidad. Por lo tanto, no es posible que ninguno de los dominios del reloj calcule un valor erróneo para la cantidad de palabras en el FIFO; simplemente se trata de si obtiene la actualización un reloj antes o después de lo que podría haberlo hecho.

Entonces, en el lado de escritura, el puntero de la cabeza se incrementa directamente, aumentando la profundidad del FIFO, pero el puntero de la cola actualizado que viene del otro lado puede retrasarse. Esto solo puede causar que el lado de escritura sobreestime la cantidad de palabras en el FIFO y, por lo tanto, el FIFO nunca se desbordará.

De manera similar, en el lado de lectura, el puntero de la cola se incrementa directamente, disminuyendo la profundidad del FIFO, pero el puntero de la cabeza actualizado puede retrasarse. Esto solo puede hacer que el lado de lectura subestime la cantidad de palabras en el FIFO y, como resultado, nunca se desbordará.

De hecho, puede colocar cualquier cantidad de etapas de sincronización en la ruta de las transferencias de código Gray, y el único efecto que esto tendrá es aumentar la latencia a través de FIFO. Este es incluso un parámetro configurable en el generador FIFO de doble reloj de Xilinx.

Está bien, creo que lo entiendo. Por lo tanto, varios bits pueden cambiar cuando el contador se cruza al dominio de reloj más lento, pero solo 1 bit presentará el riesgo de ser metaestable debido al hecho de que solo 1 bit cambia en la codificación gris de dominio rápido. Todos los demás bits deberían haberse mantenido estables durante más tiempo y, por lo tanto, se ha reducido la posibilidad de violar el tiempo de configuración/retención de los registros de dominio de reloj lento. Al pasar el valor del código gris a través de un registro doble, se eliminará el error metaestable de un solo bit como suele ocurrir, y no tendrá que preocuparse por la desviación del bus de varios bits.
Usted mencionó "con la codificación de código Gray, solo cambia un bit entre cualquier par de valores". ¿Cómo puede ser esto cierto para el contador de código gris que cambia rápidamente y se captura con el reloj, digamos, 5 veces más lento? Eso significa que el flop de captura ve cada quinto valor del contador gris y esto no es solo un cambio de bit. Estoy de acuerdo con la explicación en el contexto de una transición de dominio lenta a rápida, pero no al revés. ¿Puedes aclarar por favor?
@Khach: es un punto sutil, pero la pregunta no es si los bits están cambiando del valor capturado anterior. Se trata de si estamos viendo una transición de un valor del contador al siguiente en el dominio del reloj de origen, y con el código Gray, solo puede haber un bit haciendo esa transición en un momento dado.
¿Por qué algunos módulos como el de Xilinx xpm_cdc_grayrequieren que el reloj de destino registre al menos 2 veces los datos de origen? No parece necesario y este requisito simula un reloj de origen más lento (src_clk<=dst_clk/2)... Creo que cuando el reloj de origen es mucho más rápido que el reloj de destino, es posible que tengamos problemas en el SLA con setup/ mantenga los tiempos, pero mientras la diferencia sea razonable, deberíamos estar bien.
@Alexis: Honestamente, no lo sé. Qué reloj es más rápido realmente no debería hacer ninguna diferencia. Después de todo, cuando cruza entre los dominios de dos relojes no relacionados, no hay garantías con respecto a la configuración/retención de todos modos. Es por eso que cualquier solución debe diseñarse para hacer frente a las oportunidades resultantes de metaestabilidad, sesgo de tiempo, etc.
De hecho, gracias.