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 son muchas (al menos una docena) de bordes de reloj separados:
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 con 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 retraso, 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 violaciones de configuración y tiempo de espera, porque no reconoce el sincronizador. Peor aún, el manual de Quartus dice
Concéntrese en mejorar los caminos que muestran la peor holgura. El Fitter trabaja más duro en caminos con la peor holgura. Si arregla estas rutas, el Fitter podría mejorar las otras rutas de sincronización que fallan en el diseño.
Por lo tanto, quiero agregar las restricciones de tiempo adecuadas a mi proyecto para que Quartus gaste su esfuerzo de Fitter en otras áreas del diseño.
Estoy bastante seguro de que set_multicycle_path
es el comando SDC (Restricción de diseño de sinopsis) 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 usando este comando para describir la lógica de cruce del dominio del reloj .
Realmente agradecería alguna orientación sobre cómo escribir restricciones de sincronización SDC para sincronizadores. Si ve un problema con este enfoque, hágamelo saber también.
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 sincronización SDC correctas para el código anterior?