restricción de tiempo para circuitos sincronizadores de bus

Tengo un circuito sincronizador de bus para pasar un registro amplio a través de dominios de reloj.

Proporcionaré una descripción simplificada, omitiendo la lógica de reinicio asíncrono.

Los datos se generan en un reloj. Las actualizaciones están separadas por muchos (al menos una docena) bordes de reloj:

PROCESS (src_clk)
BEGIN
   IF RISING_EDGE(clock) THEN
      IF computation_done THEN
          data <= computation;
          ready_spin <= NOT ready_spin;
      END IF;
   END IF;
END PROCESS;

La señal de control para datos nuevos, que está codificada en NRZI (por lo que una palabra válida en el bus corresponde a una transición en la señal de control). La señal de control pasa a través de una cadena DFF que actúa como sincronizador.

PROCESS (dest_clk)
BEGIN
   IF RISING_EDGE(dest_clk) THEN
      ready_spin_q3 <= ready_spin_q2;
      ready_spin_q2 <= ready_spin_q1;
      ready_spin_q1 <= ready_spin;
   END IF;
END PROCESS;

El circuito sincronizador introduce un breve retardo, lo que proporciona mucho tiempo para que el bus de datos se estabilice; el bus de datos se muestrea directamente sin riesgo de metaestabilidad:

PROCESS (dest_clk)
BEGIN
   IF RISING_EDGE(dest_clk) THEN
      IF ready_spin_q3 /= ready_spin_q2 THEN
         rx_data <= data;
      END IF;
   END IF;
END PROCESS;

Esto compila y funciona bien cuando se sintetiza en un FPGA Cyclone II. Sin embargo, TimeQuest informa sobre infracciones del tiempo de configuración y espera porque no reconoce el sincronizador. Peor aún, dice el manual de Quartus

Concéntrese en mejorar las rutas que muestran la peor holgura. El Fitter trabaja más duro en caminos con la peor holgura. Si corrige estas rutas, el instalador podría mejorar las otras rutas de temporización que fallan en el diseño.

Así que quiero agregar las restricciones de tiempo correctas a mi proyecto para que Quartus dedique su esfuerzo de Fitter a otras áreas del diseño.

Estoy bastante seguro de que set_multicycle_pathes el comando SDC (Synopsis Design Constraint) adecuado, ya que las líneas de datos tendrán múltiples ciclos del reloj de destino para estabilizarse, pero no puedo encontrar ningún ejemplo completo que use este comando para describir la lógica de cruce del dominio del reloj. .

Realmente agradecería alguna orientación sobre cómo escribir las restricciones de tiempo de SDC para sincronizadores. Si ve un problema con este enfoque, hágamelo saber.


Detalle del reloj:

Generador de reloj externo: dos canales, refclk = 20 MHz, refclk2 = refclk/2 (10 MHz y relacionados).

Altera PLL: src_clk = refclk * 9/5 = 36 MHz

Altera PLL: dest_clk = refclk2 * 10 = 100 MHz

También tengo datos que van en la otra dirección, con 100 MHz src_clk y 36 MHz dest_clk.


TL; DR: ¿Cuáles son las restricciones de tiempo SDC correctas para el código anterior?

Esto sería mejor en el sitio de diseño de FPGA propuesto, pero esa propuesta aún no ha alcanzado la versión beta.
¿Puede publicar las definiciones de reloj para src_clk y dest_clk? ¿Están relacionados de alguna manera (múltiplos sincrónicos)? Si son relojes no relacionados, es típico usar set_false_path en esta situación.
@Andy: Agregué algunos de los detalles. Gracias por ayudar con esto.

Respuestas (4)

No tengo experiencia con Quartus, así que trata esto como un consejo general.

Cuando se trabaja en rutas entre dominios de reloj, las herramientas de temporización expanden los relojes al mínimo común múltiplo de sus períodos y seleccionan el par de aristas más cercano.

Para rutas desde un reloj de 36 MHz (27,777 ns) a un reloj de 100 MHz (10 ns), si hice correctamente mis cálculos rápidos, el par de flancos ascendentes más cercano es 138,888 ns en el reloj de origen y 140 ns en el reloj de destino. ¡Eso es efectivamente una restricción de 900 MHz para esos caminos! Dependiendo del redondeo (o para relojes sin relación), podría salir peor que eso.

Hay al menos tres formas de escribir restricciones para esta estructura. Voy a llamar a los relojes fast_clky slow_clkcomo creo que es más claro para la ilustración.

Opción 1: deshabilitar el tiempo conset_false_path

La solución más fácil es usar set_false_pathpara deshabilitar el tiempo entre los relojes:

set_false_path -from [get_clocks fast_clk] -to [get_clocks slow_clk]
set_false_path -from [get_clocks slow_clk] -to [get_clocks fast_clk]

Esto no es estrictamente correcto, ya que existen requisitos de temporización para que el sincronizador funcione correctamente. Si la implementación física retrasa demasiado los datos en relación con la señal de control, el sincronizador no funcionará. Sin embargo, dado que no hay ninguna lógica en la ruta, es poco probable que se viole la restricción de tiempo. set_false_pathse usa comúnmente para este tipo de estructura, incluso en ASIC, donde la compensación de esfuerzo versus riesgo para fallas de baja probabilidad es más cautelosa que para FPGA.

Opción 2: relajar la restricción conset_multicycle_path

Puede permitir tiempo adicional para ciertas rutas con set_multicycle_path. Es más común usar rutas multiciclo con relojes estrechamente relacionados (por ejemplo, relojes 1X y 2X que interactúan), pero funcionará aquí si la herramienta lo admite lo suficiente.

set_multicycle_path 2 -from [get_clocks slow_clk] -to [get_clocks fast_clk] -end -setup
set_multicycle_path 1 -from [get_clocks slow_clk] -to [get_clocks fast_clk] -end -hold

La relación de borde predeterminada para la configuración es ciclo único, es decir, set_multicycle_path 1. Estos comandos permiten un ciclo más del reloj del punto final ( -end) para las rutas de configuración. El -holdajuste con un número uno menos que la restricción de configuración casi siempre es necesario cuando se configuran rutas de varios ciclos, para obtener más información, consulte a continuación.

Para restringir las rutas en la otra dirección de manera similar (relajando la restricción en un período del reloj más rápido), cambie -enda -start:

set_multicycle_path 2 -from [get_clocks fast_clk] -to [get_clocks slow_clk] -start -setup
set_multicycle_path 1 -from [get_clocks fast_clk] -to [get_clocks slow_clk] -start -hold

Opción 3: especifique el requisito directamente conset_max_delay

Esto es similar al efecto de set_multicycle_pathpero ahorra tener que pensar en las relaciones de borde y el efecto en las restricciones de espera.

set_max_delay 10 -from [get_clocks fast_clk] -to [get_clocks slow_clk]
set_max_delay 10 -from [get_clocks slow_clk] -to [get_clocks fast_clk]

Es posible que desee emparejar esto con set_min_delaycheques en espera, o dejar el cheque en espera predeterminado en su lugar. También puede hacer set_false_path -holdpara deshabilitar los controles de retención, si su herramienta lo admite.


Detalles sangrientos de la selección de bordes para rutas de varios ciclos

Para comprender el ajuste de retención que se combina con cada ajuste de configuración, considere este ejemplo simple con una relación de 3:2. Cada dígito representa un flanco ascendente del reloj:

1     2     3
4   5   6   7

La verificación de configuración predeterminada usa los bordes 2 y 6. La verificación de retención predeterminada usa los bordes 1 y 4.

La aplicación de una restricción de varios ciclos de 2 -endajusta la configuración predeterminada y las comprobaciones de retención para usar el siguiente borde después de lo que estaban usando originalmente, lo que significa que la verificación de configuración ahora usa los bordes 2 y 7 y la verificación de retención usa los bordes 1 y 5. Para dos relojes a la misma frecuencia, este ajuste tiene sentido: cada lanzamiento de datos corresponde a una captura de datos, y si el borde de captura se mueve hacia afuera en uno, la verificación de espera también debe moverse hacia afuera en uno. Este tipo de restricción podría tener sentido para dos ramas de un solo reloj si una de las ramas tiene un gran retraso. Sin embargo, para la situación aquí, una verificación de retención usando los bordes 1 y 5 no es deseable, ya que la única forma de solucionarlo es agregar un ciclo de reloj completo de retraso en la ruta.

La restricción de espera multiciclo de 1 (para espera, el valor predeterminado es 0) ajusta el borde del reloj de destino utilizado para verificaciones de espera hacia atrás en un borde. La combinación de restricciones MCP de configuración de 2 ciclos y MCP de retención de 1 ciclo dará como resultado una verificación de configuración usando los bordes 2 y 7, y una verificación de retención usando los bordes 1 y 4.

Esta respuesta es excelente. Añadiré un consejo. Utilice TimeQuest Timing Analyzer para crear nuevas reglas para su archivo sdc. Puede ser difícil obtener la sintaxis correcta si solo sigue el manual de sdc. Además: recomiendo leer este documento: fpgawiki.intel.com/wiki/File:TimeQuest_User_Guide.pdf

No sé la respuesta para Altera, pero en Xilinx Land puedes configurar el retraso de tiempo de un dominio de reloj al siguiente. Tendrá que calcular las matemáticas (depende del diseño), pero generalmente es el más corto de los dos períodos de reloj. Piense en este tiempo como el sesgo máximo entre dos señales cualesquiera (incluida su señal de control), y puede determinar si su circuito de sincronización podrá manejarlo.

set_mulicycle_path no es lo correcto porque eso normalmente se ocuparía de casos en los que tanto el origen como el destino están en el mismo dominio de reloj. Nuevamente, me baso en mi experiencia en Xilinx, por lo que su millaje puede variar.

Sospecho que el problema es que, si bien es posible que sepa que las señales del bus no van a cambiar en ningún lugar cerca del punto en el que están bloqueadas, el software no lo sabe. Lo mejor que puede hacer es decirle explícitamente al software que las señales del bus entrantes están sincronizadas con el reloj del bus y deshabilitar cualquier optimización antes del lugar donde realmente las bloquea (en teoría, un optimizador podría reemplazar su circuito con uno que sería equivalente si las entradas realmente fueran síncronas, pero que podrían generar un bucle si cambian en ciclos de reloj que no le importarían al circuito que dibujó).

¿No set_multicycle_pathsería la manera de decirle al sintetizador/analizador de tiempo con qué frecuencia pueden cambiar las señales de origen? Y no estoy seguro de lo que quiere decir con "reloj de bus", aquí hay un bus de señal que cruza los dominios del reloj, entonces, ¿a qué reloj llama "reloj de bus"? Creo que tiene razón en que aún podría haber metaestabilidad si el sintetizador presenta fallas durante los períodos en los que no estoy actualizando data. Supongo que podría instanciar específicamente bloques DFF allí :(
@BenVoigt: Creo que "set_multicycle_path" se usa más a menudo para decirle al validador de tiempo que se debe permitir que una cadena de lógica combinatoria entre dos puntos de enganche tome N (Tc) -Ts-Tp (N veces el tiempo de ciclo menos el tiempo de muestra menos el enganche tiempo de propagación) en lugar de solo Tc-Ts-Th. No sé cómo tal cosa interactuaría con el enganche de diferentes relojes.

Creo que es seguro poner un set_false_path sobre el sincronizador.

También podría poner "set_global_assignment -name SYNCHRONIZER_IDENTIFICATION AUTO" en el qsf para ayudar a Quartus a detectar el sincronizador.

Como se veria eso? set_false_path -from ready_spin -to ready_spin_q2? y set_false_path -from data -to rx_data?
set_false_path -from src_clk -to ready_spinNo estoy seguro de que sea apropiado colocar la ruta falsa en los datos ya que no los está sincronizando.