Cette page est la deuxième d'une série de cinq pages consacrée au métier de concepteur FPGA. Sur cette page, je passerai en revue les différents sujets théoriques que je pense que tout concepteur FPGA devrait maîtriser, et je tenterai aussi d'expliquer pourquoi je crois que chacun est important.
Théorie de la logique
Connaître la théorie n'est pas un luxe. C'est la fondation sur laquelle tout le reste se construit, même si ce n'est pas toujours l'impression qu'on a pendant qu'on se bat avec un outil de développement qui refuse de coopérer ou quand l'électronique semble faire à sa tête.
Un ingénieur FPGA doit être capable d'imaginer comment le Verilog qu'il écrit est implémenté en éléments logiques. Pas dans les moindres détails, mais suffisamment pour dire quelles parties vont ralentir la conception et limiter la fréquence d'horloge, et quelles parties vont engloutir beaucoup de ressources logiques. C'est crucial, par exemple, pour savoir quand une tâche doit être pipelinée (pipelined) en ajoutant des registres. Le pipeline (pipeline) complique généralement la conception, mais c'est souvent le seul moyen d'atteindre la vitesse requise. D'autres décisions de conception importantes reposent sur cette capacité.
C'est aussi crucial pour suivre ce que le synthétiseur (synthesizer) a fait, et pourquoi. Par exemple, savoir ce que le synthétiseur (synthesizer) a tendance à éliminer par optimisation vous permet d'écrire du code Verilog à la fois lisible et efficace. Si vous ne savez pas ce que le synthétiseur (synthesizer) fera de votre code, vous écrivez à l'aveugle.
Alors, quels sujets sont pertinents ? Je suggère de commencer par cette liste. Je ne prétends pas qu'elle couvre tout.
- Portes logiques (AND, OR, XOR, etc.), bascules (flip-flops), ROM/RAM, LUT et multiplexeurs (muxes). Ce sont les briques de base de tout, utilisées dans les fiches techniques, les guides utilisateurs et quand les outils expliquent ce qu'ils ont fait. Pas compliqué, et vous serez perdu sans cela.
- Logique combinatoire (combinatorial logic) vs. logique séquentielle, et les principes de conception synchrone. Ce sont des concepts centraux dans toute conception logique.
- Machines d'état (state machines). Comprenez comment ces diagrammes se transforment en code Verilog, et ayez une bonne intuition du fonctionnement des machines d'état (state machines). Presque toujours, quand une logique se comporte comme du logiciel, en ce sens qu'elle fait quelque chose de séquentiel qui dépend des signaux d'entrée, il y a une machine d'état (state machine) derrière.
- Algèbre booléenne. Des choses comme x && (y || z) = x && y || x && z, et la loi de De Morgan : !(x && y) = !x || !y. Elles sont souvent utilisées pour simplifier le code. C'est comme connaître les bases de l'algèbre.
- Arithmétique en virgule fixe (fixed-point), complément à deux, débordement (overflow) et saturation. Comment l'addition et la soustraction sont implémentées. Comprenez le problème du délai de propagation (propagation delay) de la retenue. Un coup d'œil superficiel sur la façon dont un multiplicateur est implémenté est aussi recommandé. Les opérations arithmétiques sont partout dans une conception logique, et vous devez savoir comment elles se comportent exactement, combien de ressources ces opérations consomment, et dans quelle mesure elles ralentissent votre conception.
Paradigmes et techniques de logique
Outre la connaissance de la théorie pure de la logique, il y a quelques sujets nécessaires pour écrire du code qui fonctionne de manière fiable et efficace, et qui se comporte dans le matériel comme dans la simulation. C'est presque acquis dans le monde du logiciel, mais les concepteurs FPGA vivent dans un territoire différent. Tout concepteur FPGA doit avoir ces sujets en tête, tout le temps.
Le paradigme RTL, Register Transfer Level, est l'idée centrale. En bref, cela signifie que tout ce qui stocke une valeur ne change cette valeur qu'en réponse à un front d'horloge. Une réinitialisation asynchrone (asynchronous reset) peut être l'unique exception soigneusement contrôlée. Une fois que vous avez intériorisé cette façon de penser, vous avez de bonnes chances de réussir.
La réinitialisation (reset) est un sujet à part entière. Réinitialisation synchrone (synchronous reset) versus asynchrone (asynchronous reset), et synchronisation de réinitialisation, sont des choses que vous devez régler dans chaque conception sur laquelle vous travaillez. Si vous ne le faites pas, votre conception fonctionnera bien la plupart du temps, avec des ratés sporadiques de temps en temps. Vous aurez un système fonctionnel à livrer, mais vous ne pourrez pas le publier à cause de ces défaillances sporadiques. Votre projet prendra de plus en plus de retard, et vous n'aurez aucune idée de ce qui ne va pas. Une mauvaise réinitialisation n'est pas ce qui vient à l'esprit dans ces situations. Vous voulez vraiment comprendre ce sujet en profondeur. Il y a une courte série de pages sur ce sujet sur ce site.
Étroitement liée est la question des validations d'horloge (clock enables) versus les horloges validées (gated clocks). Ce sont essentiellement deux techniques différentes pour empêcher la conception logique de tourner à chaque cycle d'horloge. Le FPGA dispose de ressources dédiées pour le clock gating, mais mal le faire est un bon moyen de créer des problèmes mystérieux. L'habitude sûre est d'utiliser des validations d'horloge (clock enables) dans votre logique, mais si vous voulez profiter de la fréquence d'horloge effective plus basse pour assouplir les contraintes temporelles (timing constraints), vous pouvez aussi rencontrer des problèmes.
Le codage des machines d'état (state machines) mérite aussi une mention. Le codage binaire, one-hot et Gray ont tous leur place, et le choix a des implications à la fois sur la vitesse et sur l'utilisation des ressources. Les outils choisiront souvent pour vous, mais vous devez savoir ce que signifient les options. En particulier, le codage one-hot est excellent pour les grandes machines d'état (state machines). Mais si la machine d'état (state machine) n'est pas réinitialisée correctement, ce codage peut lui faire faire des choses impossibles selon le code Verilog. Cela ressemble à de la sorcellerie dans le FPGA ou à un bug dans le synthétiseur (synthesizer), mais non, c'est du codage one-hot et une réinitialisation mal appliquée.
Et enfin, le pipeline (pipeline). Ce n'est pas seulement une technique, c'est une façon de penser. Ajouter un registre est trivial, mais le fait que le traitement des données s'étale sur plusieurs cycles d'horloge crée toute une série de problèmes possibles. Par exemple, que doit faire le récepteur de ces données avant que les premières données valides soient arrivées ? Que se passe-t-il si les données d'entrée n'arrivent pas en continu, et que le pipeline (pipeline) doit se figer temporairement ? Comment faire cela sans une validation d'horloge (clock enable) unique avec un fan-out (fan-out) énorme vers tous les éléments logiques de la chaîne de traitement ?
Chaque scénario nécessite un type différent de conception de pipeline (pipeline), et chacun a ses propres défis et particularités.
Conception numérique
Comme mentionné ci-dessus, un concepteur FPGA doit imaginer comment le Verilog finit par devenir des éléments logiques dans le FPGA. Prenons un exemple concret.
Supposons que j'écrive simplement « assign x = a + b; » en Verilog. Comment cet additionneur est-il implémenté ? Ce FPGA particulier utilise-t-il des astuces spéciales pour implémenter un additionneur ? Utilise-t-il un bloc matériel dédié, un bloc DSP par exemple ? Et si c'est le cas, dans quelle mesure cela aide-t-il si le résultat de l'additionneur est un registre plutôt qu'un fil ? Que se passe-t-il si j'additionne trois nombres, comme dans « assign x = a + b + c; » ? Le FPGA a-t-il un raccourci pour additionner trois nombres ? La réponse est très probablement non, donc ce sera implémenté comme quelque chose du genre (a + b) + c. Deux opérations logiques en cascade peuvent ralentir considérablement la conception. Mais comment cela fonctionne-t-il sur votre FPGA spécifique ?
Être conscient des ressources disponibles dans le FPGA spécifique que vous ciblez est important. Cela façonne la façon dont vous écrivez le Verilog, afin que le synthétiseur (synthesizer) puisse créer une logique rapide et efficace. Le synthétiseur (synthesizer) n'est pas un magicien qui résout n'importe quel problème que vous lui soumettez. Si vous écrivez du Verilog judicieusement et connaissez ses limites, vous obtenez une conception qui consomme peu de ressources, utilise relativement peu d'énergie et fonctionne à une fréquence d'horloge élevée. Cela vient avec l'expérience, et la connaissance de la conception numérique accélère le processus d'acquisition de ce genre de sagesse.
En pratique, nous sommes généralement forcés d'examiner l'implémentation logique à l'intérieur du FPGA uniquement lors de la résolution de problèmes de clôture temporelle (timing closure), parce qu'il faut comprendre pourquoi le résultat était lent ou consommait trop de ressources. Nous passons donc en revue les petits détails de l'implémentation logique, un par un, à la recherche d'une perte de temps ou de ressources. Mais c'est aussi une bonne idée d'analyser les résultats volontairement de temps en temps, juste pour acquérir plus de connaissances, ou pour vérifier que rien de fou ne s'est produit. Cela paie à long terme.
Connaître son FPGA
Un autre aspect de l'imagination de la façon dont le Verilog se transforme en éléments logiques concerne les ressources logiques de base. Cela signifie connaître les briques de base du FPGA, et savoir à quoi elles servent.
D'abord, la structure d'un FPGA lui-même : les éléments de base, les CLB, et les tranches (slices) de votre FPGA. Lorsque vous écrivez du code Verilog, c'est un énorme avantage si vous pouvez imaginer comment ces éléments sont utilisés pour implémenter la logique requise. Ainsi, vous pouvez dire si ce que vous écrivez peut devenir le goulot d'étranglement dans la clôture temporelle (timing closure) de la conception, ou si ce bout de code ne vous dérangera plus jamais.
La plupart des FPGA sont structurés plus ou moins de la même manière. Tous ont un moyen d'implémenter efficacement des additionneurs arithmétiques, des multiplexeurs, des démultiplexeurs, etc., car ces fonctions sont beaucoup utilisées. Par exemple, beaucoup de FPGA ont des multiplicateurs en tant que bloc matériel, permettant à des opérations comme « assign x = a * b; » de tourner à une fréquence d'horloge rapide.
Mais les caractéristiques exactes de ces multiplicateurs peuvent différer. Sur certains FPGA, les opérandes de ces blocs multiplicateurs sont des entiers signés de 18 bits. Ainsi, une multiplication avec des opérandes de cette largeur ou moins tournera à une fréquence d'horloge bien plus élevée que si l'un des opérandes fait 19 bits de large. C'est un autre exemple de pourquoi il est important de connaître les blocs logiques du FPGA : un seul bit supplémentaire peut réduire considérablement la fréquence d'horloge. Notez que pour une famille FPGA différente, cela peut être un jeu complètement différent avec d'autres largeurs d'opérandes.
Les ressources de routage comptent aussi. Les éléments logiques ne sont que la moitié de l'histoire ; les fils entre eux sont l'autre moitié. Assez souvent, une conception ne peut pas atteindre sa fréquence d'horloge parce que le routage devient congestionné et donc lent. C'est quelque chose à prendre en compte si vous avez l'intention d'utiliser votre FPGA à près de 100 % de sa capacité logique, et que vous avez beaucoup de bus de données larges dans votre conception. Certaines ressources de routage (« fils ») dans le FPGA sont rapides, d'autres plus lentes. Quand les rapides s'épuisent, toute la conception ralentit.
Vous devez aussi comprendre les FIFO et les BRAM. Ce sont les ressources de mémoire à l'intérieur du FPGA, et vous les utiliserez constamment, à la fois pour stocker et mettre en tampon des données et pour traverser les domaines d'horloge (clock domains). Savoir travailler avec une FIFO, c'est la base. Il y a une série de pages sur ce site à ce sujet.
Les ressources d'horloge sont un petit univers à part : PLL, tampons d'horloge, et les réseaux d'horloge globaux et régionaux. La PLL est le composant qui transforme une horloge entrante en horloges dont votre logique a réellement besoin. Elle multiplie et divise les fréquences, et permet aussi un déphasage. Il est aussi important de savoir quelles horloges sont alignées en phase et lesquelles ne le sont pas. Par exemple, supposons qu'une PLL émette deux horloges, et que l'une ait deux fois la fréquence de l'autre : est-il sûr pour un registre cadencé par la première horloge d'échantillonner la sortie d'un registre cadencé par la seconde ? C'est généralement le cas, mais cela dépend si ces deux horloges sont alignées en phase. Mais vous devez savoir comment vérifier que c'est bien le cas. Il y a une page sur ce site qui traite ce sujet.
Ensuite, nous avons les ressources des blocs d'E/S. Dans les conceptions impliquant des signaux d'E/S à haute vitesse, comme DDR et SERDES, vous devez comprendre ce que les blocs d'E/S peuvent faire pour vous, et comment ils permettent des E/S à des débits bien supérieurs à la fréquence d'horloge de votre conception. Ils peuvent aussi être configurés pour aider à l'adaptation d'impédance en ajoutant une terminaison et d'autres fonctions électroniques de bas niveau.
Et si vous avez besoin de débits supérieurs à un gigabit par seconde, les émetteurs-récepteurs multi-gigabits (MGT) sont faits pour vous. C'est un sujet relativement avancé et compliqué, pas pour les débutants, à moins que ce ne soit requis pour un projet spécifique. Il y a une série de pages sur ce site à ce sujet aussi.
Et un dernier sujet un peu ennuyeux : la mémoire de configuration et le chargement du flux de configuration (bitstream). Une fois votre conception terminée, vous ne voulez pas charger le flux de configuration (bitstream) dans le FPGA depuis l'ordinateur à chaque fois. Le FPGA peut donc le charger lui-même depuis une mémoire flash. Ou depuis une carte SD. Ou un composant séparé sur la carte peut pousser le flux de configuration (bitstream) dans le FPGA, une solution souvent choisie quand il y a un processeur séparé sur la carte.
Il n'y a rien d'amusant dans les techniques de chargement du FPGA, mais si vous travaillez dans une petite équipe, vous en serez aussi responsable. Et il y a souvent des exigences sur le délai dans lequel le FPGA doit être opérationnel après la mise sous tension de la carte. Ce sera à vous de le déterminer.
Une autre raison d'être conscient de ce sujet est que le FPGA est souvent chargé automatiquement depuis la mémoire flash à la mise sous tension, en particulier sur les cartes d'évaluation. Pour rendre cela encore plus délicat, les cartes FPGA ont souvent plus d'une source de mémoire possible pour charger le flux de configuration (bitstream). De très longues sessions de débogage surviennent quand les gens ne savent pas qu'une ancienne version de leur projet est chargée dans le FPGA : quels que soient les changements qu'ils font dans la conception, le FPGA se comporte de la même façon, parce qu'ils mettent à jour la mauvaise mémoire flash à chaque fois.
Timing
D'abord, un mot rapide sur ce qu'est le timing (dans le contexte d'une conception logique). Pour faire court, tout signal numérique à l'intérieur et à l'extérieur du FPGA doit être électriquement stable pendant des intervalles de temps spécifiques, généralement en relation avec les fronts d'horloge. Sinon, le comportement de la logique devient imprévisible. Les outils de développement veillent à ce que ces exigences temporelles soient satisfaites partout où c'est nécessaire. Mais pour que cela se produise, nous devons donner à ces outils des informations spécifiques, et le faire très précisément. De plus, la conception logique doit aussi être faite d'une manière qui permette aux outils de respecter les exigences temporelles. C'est en résumé ce dont il s'agit avec le timing.
Le timing est probablement la partie la plus difficile du métier de concepteur FPGA. C'est aussi le domaine le plus important à vraiment maîtriser et à implémenter correctement. Malheureusement, il est assez facile de négliger ce sujet et d'obtenir quand même une conception qui fonctionne assez bien, ou peut-être juste assez bien pour donner l'impression que vous avez presque fini. Tout fonctionne bien, mais il semble y avoir des forces surnaturelles dans le FPGA qui causent des défaillances soudaines à la pleine lune. J'appelle cet état d'esprit le « mode magie noire », et il y a une page séparée à ce sujet.
Un bon jour, une conception FPGA écrite sans se soucier du timing peut être corrigée facilement en ajoutant quelques contraintes temporelles (timing constraints). Parfois, presque tout doit être refait à zéro, parce que lorsque les exigences temporelles correctes sont imposées, les outils de développement n'arrivent pas à la faire fonctionner à la fréquence d'horloge requise. Le code Verilog lui-même doit donc être refactorisé.
Et un jour vraiment mauvais, le PCB doit être partiellement reconçu, parce qu'il est impossible de garantir que tous les signaux physiques de la carte ont une tension stable dans les créneaux temporels où ils doivent être stables. Une analyse de timing correcte avant que le PCB ne soit validé pour la production l'aurait révélé, mais si cela a été négligé, le matériel peut ne pas être à la hauteur.
Mais si vous faites le timing avec soin et correctement, le FPGA est le composant le plus fiable du monde. Beaucoup de concepteurs FPGA ont peur de faire le moindre changement dans la conception, peur à chaque fois qu'un nouveau lot de puces FPGA est utilisé en production. Un refroidissement démesuré est appliqué, car horreur si le FPGA chauffe un peu. Je dis : assurez-vous de faire le timing correctement, et oubliez tous les soucis.
Devez-vous maîtriser cela parfaitement dès le premier jour ? Je dirais en fait oui. En principe, je conviendrais que si vous êtes dans une équipe de concepteurs FPGA, et qu'un seul est vraiment bon en timing, cela suffit. Soyez ce concepteur FPGA, pour une raison simple : il y a de fortes chances que personne d'autre ne le soit.
Il y a une assez longue série de pages sur le timing sur ce site, donc c'est un peu inutile de détailler les sujets ici. Voici donc juste une brève liste des sujets avec lesquels je pense que tout concepteur FPGA devrait être à l'aise :
- Délai de propagation (propagation delay), tsu et thold
- Écriture de contraintes temporelles (timing constraints) : contraintes de période, horloges non liées (unrelated clocks), exceptions de timing, chemins faux (false paths), etc.
- Lecture des rapports de timing : setup, hold, marge (slack), interaction entre domaines d'horloge (clock domain), chemins critiques (critical paths).
- Analyse de timing aux quatre coins (four-corner)
- Fréquence d'horloge et gigue (jitter), et implications de la gigue (jitter) pour la clôture temporelle (timing closure), la perte de verrouillage, un mauvais échantillonnage (sampling) du signal, la propagation de la gigue (jitter) dans les PLL (dégradation des MGT due à la gigue (jitter), si vous avez de tels composants dans votre conception).
- Ressources d'horloge : le tampon d'horloge, l'arbre de distribution d'horloge, le décalage d'horloge (clock skew), comment la PLL compense le délai de l'arbre d'horloge, etc.
- Traversée de domaines d'horloge (clock domain crossing). Il y a une série de pages spécifiquement sur ce sujet.
Électronique
Le FPGA est un dispositif électronique, et la conception FPGA est un domaine d'expertise du génie électrique. Et c'est le genre de génie électrique qui traite des schémas et des fiches techniques, des tensions et des courants, de l'intégrité du signal et de l'adaptation d'impédance. C'est la connaissance que tout concepteur de PCB doit avoir, et la vie d'un concepteur FPGA est nettement plus facile s'il possède aussi ce genre de connaissances.
Il est courant que le concepteur FPGA soit chargé de s'assurer que le FPGA s'interface correctement avec les autres composants de la carte. En fait, il n'est pas rare que les concepteurs de PCB connectent tout ce qu'ils peuvent au FPGA afin de se décharger de la responsabilité de faire fonctionner ces composants. Le concepteur FPGA est donc souvent tenu d'avoir une compréhension profonde de la façon dont les composants s'interfacent les uns avec les autres sur un PCB. C'est souvent l'ingénieur FPGA qui doit signaler les problèmes potentiels d'intégrité du signal qui doivent être traités sur des fils commutant à haute fréquence.
Lorsqu'un nouveau PCB est conçu, le concepteur FPGA de l'équipe est généralement tenu d'approuver la conception, c'est-à-dire de vérifier que les connexions au FPGA sont correctes. Toutes les broches du FPGA ne conviennent pas à tous les usages, et parfois il est requis, ou nettement mieux, que certaines connexions appartiennent à un groupe particulier (« bank ») de broches du FPGA. Ce sont des choses que le concepteur FPGA doit maîtriser, ou au moins sur lesquelles il doit avoir un avis solide.
Il n'est pas rare que les concepteurs FPGA soient d'anciens concepteurs de PCB. Le chemin (path) de la conception de cartes vers la conception FPGA est naturel, et ceux qui l'ont parcouru ont un avantage distinct. Même si le concepteur de PCB est responsable et conçoit une carte parfaitement bonne, le concepteur FPGA doit encore comprendre les défis liés aux signaux haute vitesse sur un PCB, afin de configurer correctement les blocs d'E/S du FPGA.
Comme je l'ai mentionné plus tôt, tous les ingénieurs FPGA ne travaillent pas directement avec l'électronique. Certains se limitent à développer de la logique interne, ce que j'ai appelé « logique de traitement », et parfois les entreprises embauchent un ingénieur juste pour faire de la simulation et de la vérification. Mais la plupart d'entre nous travaillent directement avec l'électronique, et dans ce cas, certaines connaissances connexes sont requises.
Cela commence par les bases absolues : tension, courant, résistances et loi d'Ohm. C'est ainsi que les signaux numériques passent d'un composant à un autre. C'est aussi une bonne idée de comprendre la capacité et comment un condensateur se charge et se décharge. Cela vous permet de comprendre comment le courant et la capacité influencent les vitesses de commutation et la consommation d'énergie.
Vous devez être capable de lire des schémas : CI, modules, inductances, alimentations, masse numérique et analogique. Les MOSFET et les transistors bipolaires apparaissent aussi parfois, et vous devriez au moins les reconnaître. Cela ne fait pas de mal de se faire une idée du comportement d'un transistor MOSFET.
Vous passerez aussi beaucoup de temps à lire des fiches techniques. La partie la plus difficile et la plus importante est de traduire les spécifications de timing de la fiche technique en contraintes temporelles (timing constraints) et/ou en une conception d'E/S appropriée sur le FPGA. Le décalage (skew) de la carte est quelque chose que vous devrez peut-être prendre en compte dans le timing de vos E/S.
Mais vous serez aussi responsable de donner un sens aux spécifications de tension et de courant de la fiche technique, et de configurer le bloc d'E/S correspondant du FPGA avec le bon standard de tension : interfaces single-ended et différentielles, LVCMOS, SSTL, LVDS, etc.
Tous les concepteurs FPGA font-ils vraiment cela correctement ? La réponse est non. Il est assez courant de voir des conceptions qui ne devraient pas fonctionner du tout à cause de leurs mésaventures électroniques, et pourtant elles semblent fonctionner parfaitement. Il n'est pas rare que la broche de sortie d'un composant alimente la broche d'entrée de l'autre composant avec une tension supérieure à la valeur maximale absolue. C'est une énorme erreur, bien sûr, et le composant recevant la tension excessive peut en principe griller à tout moment, selon la fiche technique. Et pourtant, tout fonctionne pour toujours et à jamais. Jusqu'à ce que cela casse soudainement, et que des gens intelligents trouvent des excuses idiotes pour expliquer pourquoi c'est arrivé.
J'ajouterai aussi une courte liste de sujets qui relèvent définitivement de la responsabilité du concepteur de PCB. Mais quand cette personne est moins qu'excellente, il est utile que l'ingénieur FPGA s'y connaisse aussi un peu :
- Alimentations et régulateurs de tension.
- Oscillateurs d'horloge, horloges de référence, et gigue (jitter).
- Intégrité du signal : adaptation d'impédance et terminaisons, réflexions, diaphonie (crosstalk), EMI.
- Considérations thermiques.
Alors, que doit vraiment savoir un concepteur FPGA de tout cela ? Qu'est-ce qui est crucial dès le début ? Il m'est en fait difficile de le dire. Meilleure est l'équipe autour de vous, moins vous avez besoin de connaître l'électronique. Mais je dirais que tout concepteur FPGA devrait être capable de lire des schémas et de comprendre ce qui est connecté au FPGA, et plus ou moins comprendre pourquoi c'est connecté de cette façon spécifique.
Ceci conclut la deuxième page de cette série. La page suivante aborde les compétences pratiques, dans le même esprit que ci-dessus.1