Ho un circuito di sincronizzazione bus per il passaggio di un ampio registro tra domini di clock.
Fornirò una descrizione semplificata, omettendo la logica di ripristino asincrona.
I dati vengono generati su un orologio. Gli aggiornamenti sono diversi (almeno una dozzina) di bordi dell'orologio a parte:
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;
Il segnale di controllo per nuovi dati, che è codificato NRZI (quindi una parola valida sul bus corrisponde a una transizione sul segnale di controllo). Il segnale di controllo passa attraverso una catena DFF che funge da sincronizzatore.
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;
Il circuito di sincronizzazione introduce un breve ritardo, che fornisce molto tempo per stabilizzare il bus dati; il bus dati viene campionato direttamente senza rischio di metastabilità:
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;
Questo si compila e funziona bene se sintetizzato in un FPGA Cyclone II. Tuttavia, TimeQuest segnala l'installazione e la conservazione delle violazioni del tempo, poiché non riconosce il sincronizzatore. Peggio ancora, dice il manuale di Quartus
Concentrati sul miglioramento dei percorsi che mostrano il peggior gioco. The Fitter lavora duramente sui percorsi con il peggior gioco. Se si correggono questi percorsi, Fitter potrebbe essere in grado di migliorare gli altri percorsi di temporizzazione non riusciti nella progettazione.
Quindi voglio aggiungere i giusti vincoli di temporizzazione al mio progetto in modo che Quartus spenda i suoi sforzi di Fitter in altre aree del progetto.
Sono abbastanza sicuro che set_multicycle_path
sia il comando SDC (Synopsis Design Constraint) corretto, poiché le linee dati avranno più cicli dell'orologio di destinazione per stabilizzarsi, ma non riesco a trovare alcun esempio completo usando questo comando per descrivere la logica di attraversamento del dominio dell'orologio .
Gradirei davvero alcune indicazioni sulla scrittura dei vincoli di temporizzazione SDC per i sincronizzatori. Se vedi un problema con questo approccio, per favore fammi sapere.
Orologio dettaglio:
Generatore di clock esterno: due canali, refclk = 20 MHz, refclk2 = refclk / 2 (10 MHz e relativi).
Altera PLL: src_clk = refclk * 9/5 = 36 MHz
Altera PLL: dest_clk = refclk2 * 10 = 100 MHz
Ho anche dati che vanno nella direzione opposta, con 100 MHz src_clk e 36 MHz dest_clk.
TL; DR: quali sono i vincoli di temporizzazione SDC corretti per il codice sopra?