Cette page fait partie d’une série de pages consacrée au timing. Les pages précédentes ont expliqué la théorie derrière les calculs de timing, montré comment écrire plusieurs contraintes temporelles et abordé les principes de la convergence temporelle (timing closure). La page précédente a expliqué quelques principes fondamentaux concernant les contraintes temporelles d’entrées-sorties. Cette page poursuit avec les aspects pratiques de ce sujet.
Introduction
Le but des contraintes temporelles d’entrées-sorties est de garantir une interface fiable avec le monde extérieur : elles assurent que chaque signal provenant du monde extérieur arrive de manière fiable à la bascule concernée du FPGA. De même, elles font en sorte que chaque signal du FPGA vers le monde extérieur arrive de manière fiable à la bascule du composant externe.
Les contraintes temporelles d’entrées-sorties sont le type de contraintes temporelles (timing constraints) le plus difficile : certains paramètres temporels dépendent des composants électroniques externes présents sur la carte. Il faut généralement lire les fiches techniques (datasheets) de ces composants externes afin de déterminer les bonnes exigences de timing. Souvent, un calcul « papier-crayon » est nécessaire pour obtenir la contrainte temporelle correcte.
Il est tentant d’éviter cette tâche compliquée et de préférer une alternative simple : le tâtonnement. Ce raccourci consiste à laisser les outils faire ce qu’ils veulent, puis à voir si cela fonctionne. S’il y a un problème avec un port d’entrée, on utilise le front d’horloge opposé sur la bascule qui reçoit le signal d’entrée. De même, si une sortie ne fonctionne pas bien, on utilise le front opposé sur la bascule de sortie. Cette façon de faire permet souvent d’obtenir rapidement et simplement un montage électronique qui fonctionne.
Le problème de cette approche est que le comportement temporel change avec la température. Il existe aussi des incertitudes liées au procédé de fabrication des composants à semi-conducteurs. Cela vaut pour le FPGA comme pour l’électronique externe. Des contraintes temporelles inadéquates peuvent donc conduire à un « mode magie noire ». Cela vaut pour toutes les contraintes temporelles, mais c’est plus fréquent avec les contraintes d’entrées-sorties.
Le pire avec le fait d’éviter les calculs papier-crayon, c’est qu’il est parfois impossible de garantir les exigences temporelles à cause de la conception de la carte. Si une telle situation est découverte pendant le processus de conception de la carte, il existe souvent une solution simple (modifier le câblage vers le FPGA ou repenser la distribution des horloges). Mais si un défaut de ce genre est découvert après la fabrication du PCB, il n’y a peut-être plus aucun moyen de le corriger. Autrement dit, il devient impossible de garantir que l’électronique fonctionne de manière fiable.
Ce que contient cette page
Cette page décrit les contraintes temporelles de base pour les ports d’entrées-sorties. La syntaxe présentée ici est SDC, utilisée par Vivado et Quartus, ainsi que par d’autres outils FPGA.
Cette page commence par les contraintes temporelles dédiées aux entrées-sorties : set_input_delay et set_output_delay. La signification de ces contraintes y est expliquée. Suivent des renvois vers deux pages distinctes qui montrent des exemples de rapports de timing produits par Vivado et Quartus.
Il est aussi possible de définir des contraintes temporelles avec set_max_delay et set_min_delay. Ces commandes sont plus adaptées dans certains scénarios. Nous les avons déjà rencontrées pour les chemins internes au FPGA. Leur signification en tant que contraintes temporelles d’entrées-sorties est également expliquée plus bas.
Cette page ne traite que des aspects techniques de ces contraintes temporelles d’entrées-sorties. Pour la partie théorique, reportez-vous à la page précédente, qui montre aussi comment définir des chemins faux (false paths) pour les ports d’entrées-sorties.
Signification de set_input_delay et set_output_delay
Ces deux commandes conviennent lorsque l’interface avec le composant externe est système synchrone. En bref,
- set_input_delay -clock … -max … : le délai maximal de l’horloge vers la sortie (clock-to-output) du composant externe connecté au port d’entrée, plus le délai de la piste sur la carte.
- set_input_delay -clock … -min … : le délai minimal de l’horloge vers la sortie du composant externe connecté au port d’entrée. Si la fiche technique ne donne pas cette information, choisissez zéro (au cas où une future révision de ce composant serait fabriquée avec un procédé vraiment rapide).
- set_output_delay -clock … -max … : le tsu du composant externe qui reçoit le signal de sortie, plus le délai de la piste sur la carte.
- set_output_delay -clock … -min … : –thold du composant externe qui reçoit le signal de sortie. Notez le signe moins. Par exemple, fixez cette contrainte à -1 si le temps de maintien est de 1 ns.
Il est important de noter que ces définitions ne sont correctes que si ces deux conditions sont réunies :
- L’interface est système synchrone.
- La commande create_clock qui définit l’horloge désigne le signal d’horloge avec une commande get_ports (et non un signal interne au FPGA avec, par exemple, get_pins).
Ces deux conditions sont nécessaires pour que les délais d’horloge soient calculés correctement.
Notez aussi que si ni -min ni -max n’est utilisé, la commande est interprétée comme s’il y avait deux commandes : une avec l’attribut -min et une seconde avec l’attribut -max. Ce n’est probablement pas ce que vous voulez.
Les définitions de ces commandes sont un peu déroutantes : set_input_delay définit le moment où le signal de données est autorisé à changer après un front d’horloge. Quant à set_output_delay, il définit le moment où un front d’horloge est autorisé après que le signal de données a changé. L’idée derrière ces définitions est sans doute que les chiffres issus de la fiche technique peuvent être utilisés directement dans les contraintes temporelles.
Les commandes set_input_delay et set_output_delay possèdent plusieurs options qui ne sont pas abordées ici. En particulier, le front descendant de l’horloge peut être choisi comme référence temporelle. Reportez-vous à la documentation de l’outil pour plus d’informations.
Utilisez toujours min et max
Insister sur l’utilisation conjointe de -min et de -max pour chaque contrainte temporelle peut sembler exagéré. Par exemple, si le tsu du composant externe vaut 8 ns, qu’est-ce qui ne va pas avec ceci ?
set_output_delay -clock theclk 8 [get_ports test_out]
Cela définit correctement le temps de préparation. Quant au temps de maintien, il est involontairement défini à –8 ns. Cela autorise le port de sortie à changer d’état 8 ns avant l’horloge. Mais qui s’en soucie ? Cela ne peut pas arriver, n’est-ce pas ?
Eh bien, si, cela peut arriver. J’ai déjà évoqué l’utilisation d’une PLL pour générer l’horloge interne à partir d’une horloge provenant d’une broche d’entrée (c’est-à-dire l’horloge visible sur la carte). Cela permet à la PLL d’aligner l’horloge interne du FPGA avec l’horloge d’entrée. La PLL y parvient en décalant légèrement l’horloge afin de compenser le délai du réseau de distribution d’horloge.
En réalité, les outils FPGA peuvent se sentir libres de décaler l’horloge pour qu’elle arrive légèrement plus tôt que l’horloge de la carte, afin de satisfaire une contrainte temporelle : si l’horloge interne est avancée par rapport à l’horloge externe, le délai de l’horloge vers la sortie perçu par le composant externe devient plus petit. Cela vient de ce que la bascule interne est synchrone avec l’horloge interne, alors que le timing visible est relatif à l’horloge externe.
Mais lorsque l’horloge interne du FPGA est en avance sur l’horloge de la carte, la sortie du FPGA peut changer avant le front de l’horloge externe. Cela peut provoquer une violation du temps de maintien sur le composant qui reçoit ces sorties.
Si la commande set_output_delay définit le temps de maintien à –8 ns, cela ne signifie pas que la sortie va changer d’état 8 ns avant l’horloge. Mais cela autorise les outils à décaler l’horloge interne d’une manière qui peut violer l’exigence de thold. L’utilisation de set_output_delay avec -min empêche correctement ce phénomène.
Ajustements dus aux délais de piste
Il est important de se rappeler que les outils ne tiennent pas compte des délais de piste du PCB. Ils ne disposent pas de cette information. Ils supposent donc que ce délai est nul lorsqu’ils effectuent les calculs de timing pour set_input_delay et set_output_delay. La correction consiste à ajouter le délai de piste aux valeurs de la fiche technique pour le délai de l’horloge vers la sortie et pour tsu.
Il peut aussi être nécessaire de tenir compte du décalage d’horloge (clock skew) : sur un PCB parfait, l’horloge arrive à tous les composants avec le même délai. En réalité, un décalage d’horloge est possible entre le FPGA et le composant externe. Un tel décalage n’est pas pris en compte dans les calculs temporels des outils.
Ainsi, si l’horloge arrive plus tôt au FPGA (par rapport au composant externe), les corrections suivantes sont nécessaires :
- Pour set_input_delay -clock … -max … : ajoutez le décalage d’horloge à la valeur de délai de la commande (cela revient à un délai de l’horloge vers la sortie plus grand de la part du composant externe).
- Pour set_output_delay -clock … -min … : retranchez le décalage d’horloge de la valeur de délai de la commande, c’est-à-dire rendez-la plus négative (cela revient à un thold plus grand du composant externe).
De même, si l’horloge arrive plus tard au FPGA, les corrections suivantes sont nécessaires :
- Pour set_input_delay -clock … -min … : retranchez le décalage d’horloge de la valeur de délai de la commande (cela revient à un délai de l’horloge vers la sortie plus petit de la part du composant externe). Si la fiche technique du composant externe ne donne pas de délai minimal de l’horloge vers la sortie, utilisez l’opposé du décalage d’horloge comme valeur de cette commande.
- Pour set_output_delay -clock … -max … : ajoutez le décalage d’horloge à la valeur de délai de la commande (cela revient à un délai de piste plus grand).
Notez que le rapport de timing peut afficher un décalage d’horloge non nul, indépendamment des ajustements décrits ici. Toutefois, le décalage d’horloge qui apparaît dans le rapport de timing concerne les délais d’horloge internes au FPGA, et non ceux du PCB.
Exemples de rapports de timing
Les exemples sont fondés sur le code Verilog suivant :
module top(
input test_clk,
input test_in,
output reg test_out
);
reg test_samp;
always @(posedge test_clk)
begin
test_samp <= test_in;
test_out <= test_samp;
end
endmodule
@test_clk est l’horloge d’entrée, @test_in est une broche d’entrée et @test_out est une broche de sortie. Notez qu’aucune PLL n’est utilisée pour aligner l’horloge interne avec l’horloge de la carte ; le délai d’horloge est donc significatif.
Les contraintes temporelles sont les suivantes :
create_clock -name theclk -period 20 [get_ports test_clk] set_output_delay -clock theclk -max 8 [get_ports test_out] set_output_delay -clock theclk -min -3 [get_ports test_out] set_input_delay -clock theclk -max 4 [get_ports test_in] set_input_delay -clock theclk -min 2 [get_ports test_in]
Comme les rapports de timing sont assez longs, ils figurent sur des pages séparées :
- Cliquez ici pour l’analyse de timing de Quartus
- Cliquez ici pour l’analyse de timing de Vivado
Utiliser set_max_delay et set_min_delay
Lorsque l’interface avec le composant externe est source synchrone, l’utilisation de set_input_delay et set_output_delay est moins naturelle. set_max_delay et set_min_delay conviennent mieux à cette situation. Sur une page précédente, ces deux commandes n’ont été mentionnées que comme compléments ou ajustements (exceptions de timing) aux contraintes de période d’horloge. Tous les chemins étaient internes : ils commençaient et se terminaient sur un élément séquentiel. Lorsque ces commandes sont utilisées comme contraintes temporelles d’entrées-sorties, l’une des extrémités du chemin est un port d’entrée-sortie. Comment l’analyse temporelle est-elle alors effectuée ?
À vrai dire, il est souvent inutile d’entrer dans le détail de l’analyse temporelle de ces commandes : leur but est généralement de restreindre le comportement de l’outil en écrivant des contraintes que l’outil peut tout juste satisfaire. Les valeurs de ces contraintes sont donc trouvées en essayant de les rendre de plus en plus strictes. Avec cette méthodologie, l’analyse temporelle elle-même n’a guère d’importance.
Cela dit, il reste bon de comprendre les calculs derrière set_max_delay et set_min_delay :
Rappelons, d’après les pages précédentes, qu’une analyse de timing comporte deux parties. La première partie est le chemin source : elle calcule le temps écoulé entre un front d’horloge (sur la broche d’horloge externe) et une valeur valide et mise à jour présente sur l’entrée de données de la seconde bascule. Cette partie est la somme de trois éléments :
- Le temps nécessaire pour que le front d’horloge atteigne la première bascule (le chemin d’horloge)
- Le temps nécessaire à cette bascule pour mettre à jour sa valeur
- Le temps nécessaire pour que cette nouvelle valeur atteigne la seconde bascule
La seconde partie est le chemin de destination, qui ne contient que le temps nécessaire pour que le front d’horloge atteigne la seconde bascule. Nous savons déjà quand l’entrée de cette bascule est mise à jour (grâce au chemin source) ; la différence de temps peut donc être comparée avec le tsu ou le thold exigé, selon le cas.
Mais cela valait pour deux éléments séquentiels. Que se passe-t-il lorsque l’une des extrémités est un port d’entrée-sortie ? Pour l’analyse temporelle, le port est traité comme s’il s’agissait d’une bascule imaginaire. Le délai du chemin d’horloge vers cette bascule est nul.
Considérons la situation habituelle, où l’horloge est définie avec une commande create_clock qui s’appuie sur get_ports (comme dans presque tous mes exemples). Un délai de chemin d’horloge nul signifie que l’entrée d’horloge de cette bascule imaginaire est connectée directement à la broche d’horloge. Il n’y a donc aucun délai entre la broche d’horloge et cette bascule imaginaire.
Tous les paramètres temporels de cette bascule sont nuls : tsu, thold et le délai de l’horloge vers la sortie. Cela ne correspond à aucun composant électronique réaliste, mais cela donne un sens à set_max_delay et set_min_delay lorsqu’ils sont utilisés avec un port de sortie : le délai de l’horloge vers la sortie du port. Par exemple :
set_max_delay -to [get_ports test_out] 7 set_min_delay -to [get_ports test_out] 0
Ces deux contraintes exigent que le délai de l’horloge vers la sortie de @test_out soit compris entre 0 ns et 7 ns.
Expliquons pourquoi : Rappelons que, normalement, une commande set_max_delay est semblable à une contrainte de période pour des chemins entre des bascules précises. Que se passe-t-il donc avec le chemin d’horloge de destination ? Le calcul commence à l’instant du second front d’horloge, c’est-à-dire à 7 ns. Mais le délai du chemin d’horloge vers la seconde bascule est nul, et le tsu de cette bascule est également nul. Le résultat du calcul du chemin de destination est donc simplement 7 ns. C’est la valeur maximale autorisée pour le chemin source, calculé comme d’habitude : le chemin d’horloge source plus le chemin de données. En résumé, l’exigence est que la sortie de données soit valide 7 ns après le premier front d’horloge. C’est exactement la définition du délai de l’horloge vers la sortie du port de sortie. Si la commande create_clock de l’horloge concernée repose sur get_ports, ce délai est relatif à l’horloge présente sur le PCB.
Voir l’exemple de rapports de timing avec Vivado.
Notez que set_output_delay se rapporte au tsu ou au thold du composant externe. set_max_delay définit le délai de l’horloge vers la sortie du port de sortie du FPGA. La principale différence entre ces deux options est donc l’endroit où l’on place l’attention.
En ce qui concerne un port d’entrée, il n’y a pas d’explication intuitive de ce que signifient set_max_delay et set_min_delay : le chemin source est constitué du délai entre la broche d’entrée et l’entrée de données de la bascule qui reçoit le signal. Le chemin d’horloge de destination commence à l’instant spécifié dans la contrainte. Le délai du chemin d’horloge est ajouté à cet instant. Ce sont des calculs dépourvus de signification (voir les rapports de timing). Il est plus naturel d’utiliser set_input_delay, qui se rapporte au délai de l’horloge vers la sortie du composant externe.
Notez que l’analyse temporelle effectuée au titre de set_max_delay et set_min_delay ne dépend pas de la période d’horloge. Si la fréquence de l’horloge change, les mêmes valeurs sont utilisées lorsque les outils appliquent ces contraintes. En revanche, les calculs de set_input_delay et set_output_delay dépendent de la fréquence de l’horloge.
Cette dépendance des contraintes d’entrées-sorties à la fréquence de l’horloge peut être un avantage ou un inconvénient selon les circonstances. Si les contraintes sont écrites à partir des paramètres temporels du composant externe (et que l’interface est système synchrone), il est probablement préférable de s’appuyer sur set_input_delay et set_output_delay : ces contraintes resteront correctes même si la fréquence de l’horloge change. En revanche, lorsque le but des contraintes est de forcer les outils à faire certains choix (par exemple utiliser des registres IOB (IOB registers)), set_max_delay et set_min_delay sont plus susceptibles de convenir.
Utiliser -datapath_only
Une motivation possible d’une contrainte temporelle est d’obliger les outils FPGA à faire tout ce qu’il faut pour obtenir le délai minimal possible vers ou depuis le port d’entrée-sortie. Cela signifie en général utiliser le registre IOB. Cela peut aussi signifier éviter l’insertion d’un délai supplémentaire entre un port d’entrée et la bascule (les outils peuvent le faire pour respecter l’exigence de thold avec une meilleure marge).
Lorsqu’une contrainte temporelle est utilisée dans ce but, il n’y a pas de valeur de délai précise qui serve d’objectif. L’idée est d’empêcher les outils de faire autre chose que d’obtenir le meilleur résultat possible. Si l’outil FPGA prend en charge -datapath_only, il est préférable d’utiliser set_max_delay avec cette option. Cela élimine complètement le délai du chemin d’horloge du calcul, de sorte que seul le délai entre le port d’entrée-sortie et la bascule est pris en compte. De cette manière, l’exigence de la contrainte correspond précisément à son but : contrôler le délai entre la bascule et la broche d’entrée-sortie.
Voici un exemple simple pour Vivado :
set_max_delay -datapath_only -from [get_ports test_in] 2 set_max_delay -datapath_only -from [all_registers] \ -to [get_ports test_out] 3
Mais quel est le but de la partie qui dit « -from [all_registers] » ? Pourquoi a-t-on besoin d’un « -from » ? La réponse courte est que Vivado refusait d’accepter cette commande sans partie « -from ». Aucune exigence semblable ne s’appliquait à la commande concernant le port d’entrée.
Les rapports de timing avec datapath_only se trouvent en bas de la page contenant les exemples.
Résumé
set_input_delay et set_output_delay sont souvent considérés comme les commandes privilégiées pour les contraintes temporelles d’entrées-sorties. C’est effectivement le choix habituel lorsque l’interface est système synchrone. Dans d’autres scénarios, il peut être intéressant d’envisager set_max_delay et set_min_delay, car ils reflètent parfois mieux les limitations exigées sur le timing des ports d’entrées-sorties.
Cette page conclut cette série de pages consacrée au timing. Mais il reste une dernière page qui résume une grande partie des sujets abordés d’une manière commode pour inspecter une conception existante.