Eu tenho um circuito sincronizador de barramento para passar um amplo registro nos domínios do relógio.
Fornecerei uma descrição simplificada, omitindo a lógica de redefinição assíncrona.
Os dados são gerados em um relógio. As atualizações são muitas (pelo menos uma dúzia) de bordas do relógio separadas:
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;
O sinal de controle para novos dados, que são codificados por NRZI (uma palavra válida no barramento corresponde a uma transição no sinal de controle). O sinal de controle passa por uma cadeia DFF atuando como um 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;
O circuito sincronizador apresenta um pequeno atraso, que fornece bastante tempo para a estabilização do barramento de dados; o barramento de dados é amostrado diretamente sem risco de metaestabilidade:
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;
Isso compila e funciona bem quando sintetizado em um FPGA Cyclone II. No entanto, o TimeQuest relata violações de configuração e retenção, porque não reconhece o sincronizador. Pior, o manual Quartus diz
Concentre-se em melhorar os caminhos que mostram a pior folga. O Montador trabalha mais duro em caminhos com a pior folga. Se você corrigir esses caminhos, o Ajustador poderá melhorar os outros caminhos de tempo com falha no design.
Então, eu quero adicionar as restrições de tempo corretas ao meu projeto para que o Quartus gaste seu esforço do Fitter em outras áreas do design.
Tenho certeza de que esse set_multicycle_path
é o comando SDC (Synopsis Design Constraint) adequado, pois as linhas de dados terão vários ciclos do relógio de destino para estabilizar, mas não consigo encontrar exemplos completos usando esse comando para descrever a lógica de cruzamento de domínio do relógio .
Eu realmente aprecio algumas orientações sobre como escrever restrições de tempo SDC para sincronizadores. Se você encontrar algum problema com essa abordagem, informe-me também.
Detalhe do relógio:
Gerador de clock externo: dois canais, refclk = 20 MHz, refclk2 = refclk / 2 (10 MHz e relacionados).
Altera PLL: src_clk = refclk * 9/5 = 36 MHz
Altera PLL: dest_clk = refclk2 * 10 = 100 MHz
Eu também tenho dados indo na outra direção, com 100 MHz src_clk e 36 MHz dest_clk.
TL; DR: Quais são as restrições de tempo SDC corretas para o código acima?