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 aparte:
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 tanto, 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 un 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, lo que proporciona suficiente tiempo para que el bus de datos se estabilice; el bus de datos se muestrea directamente sin riesgo de metastabilidad:
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 se compila y funciona bien cuando se sintetiza en un FPGA Cyclone II. Sin embargo, TimeQuest informa sobre las infracciones de la configuración y el 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 instalador trabaja más duro en Caminos con la peor holgura. Si arreglas estos caminos, el instalador podría mejorar las otras rutas de tiempo que fallan en el diseño.
Por lo tanto, quiero agregar las restricciones de tiempo correctas a mi proyecto para que Quartus invierta 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 la sinopsis) adecuado, ya que las líneas de datos tendrán varios ciclos del reloj de destino para estabilizar, pero no puedo encontrar ningún ejemplo completo con 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 tiempo SDC para los 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 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?