J'ai un circuit de synchronisation de bus pour passer un registre large à travers les domaines d'horloge.
Je vais fournir une description simplifiée, en omettant la logique de réinitialisation asynchrone.
Les données sont générées sur une horloge. Les mises à jour sont éloignées de plusieurs (au moins une douzaine) fronts d'horloge:
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;
Le signal de commande pour les nouvelles données, qui est codé NRZI (donc un mot valide sur le bus correspond à une transition sur le signal de commande). Le signal de commande passe à travers une chaîne DFF faisant office de synchroniseur.
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;
Le circuit de synchronisation introduit un court délai, ce qui laisse suffisamment de temps au bus de données pour se stabiliser; le bus de données est échantillonné directement sans risque de métastabilité:
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;
Cela se compile et fonctionne bien lorsqu'il est synthétisé dans un FPGA Cyclone II. Cependant, TimeQuest signale les violations de temps de configuration et de blocage, car il ne reconnaît pas le synchroniseur. Pire, le manuel Quartus dit
Concentrez-vous sur l'amélioration des chemins qui présentent le pire ralentissement. Le monteur travaille le plus dur sur les chemins avec le pire jeu. Si vous corrigez ces chemins, l'installateur pourrait être en mesure d'améliorer les autres chemins de synchronisation défaillants dans la conception.
Je veux donc ajouter les bonnes contraintes de timing à mon projet afin que Quartus consacre ses efforts d'ajusteur à d'autres domaines de la conception.
Je suis à peu près sûr que set_multicycle_path
c'est la commande SDC (Synopsis Design Constraint) appropriée, car les lignes de données auront plusieurs cycles de l'horloge de destination pour se stabiliser, mais je ne trouve aucun exemple complet utilisant cette commande pour décrire la logique de croisement de domaine d'horloge .
J'apprécierais vraiment quelques conseils sur l'écriture des contraintes de synchronisation SDC pour les synchroniseurs. Si vous voyez un problème avec cette approche, faites-le moi savoir également.
Détail de l'horloge:
Générateur d'horloge externe: deux canaux, refclk = 20 MHz, refclk2 = refclk / 2 (10 MHz et connexes).
Altera PLL: src_clk = refclk * 9/5 = 36 MHz
Altera PLL: dest_clk = refclk2 * 10 = 100 MHz
J'ai également des données allant dans l'autre sens, avec 100 MHz src_clk et 36 MHz dest_clk.
TL; DR: Quelles sont les contraintes de synchronisation SDC correctes pour le code ci-dessus?