Introduction
Ceci est le deuxième article d’une série de quatre consacrée à la reconfiguration partielle (Partial Reconfiguration), aussi appelée Dynamic Function eXchange (DFX), avec Vivado de Xilinx. L’objectif de cet article est de parcourir et d’expliquer les étapes qui permettent d’activer la reconfiguration partielle sur un design FPGA. Il est recommandé d’avoir lu le premier article si ce n’est pas déjà fait, car il explique les concepts qui se cachent derrière ces étapes.
En 2020, Xilinx a rebaptisé la reconfiguration partielle « Dynamic Function eXchange » (DFX). C’est cette expression qui apparaît dans les menus et les notes d’information de Vivado. Le terme technique « reconfiguration partielle » est néanmoins employé ici.
Par souci de simplicité, cet article suppose qu’il n’y a qu’une seule partition reconfigurable dans le projet. Étendre cela à plusieurs partitions est relativement simple.
La procédure décrite dans cet article commence avant que le projet ne soit configuré pour la reconfiguration partielle. Pour résumer grossièrement, les étapes sont :
- Préparer le projet pour le floorplanning.
- Effectuer une première configuration du projet pour la reconfiguration partielle.
- Floorplanning.
- Vérifier et corriger le floorplanning par une implémentation du design.
- Ajouter un second module reconfigurable (ou plusieurs modules).
- Réaliser l’implémentation afin d’obtenir les fichiers de flux binaire (bitstreams).
- Examiner le projet.
Préparation du floorplanning
Le floorplanning est, plus que toute autre tâche, celle qui demande de la réflexion. Il s’agit d’un équilibre subtil entre ne pas gaspiller la surface de logique du FPGA et faire en sorte que la partition statique comme les partitions reconfigurables ne rencontrent pas d’obstacles majeurs pendant le placement et le routage (place and route).
C’est pourquoi la majeure partie de cet article est consacrée à ce sujet.
À une époque lointaine, le floorplanning était utilisé pour obtenir la convergence temporelle (timing closure). Il aidait les outils à placer la logique de façon cohérente. Les outils de conception FPGA s’étant améliorés avec le temps, cela fait de nombreuses années que je n’ai pas vu le floorplanning aider à respecter les contraintes de timing (timing constraints). Aujourd’hui, la meilleure stratégie pour atteindre les contraintes de timing est presque toujours de laisser les outils décider.
Avec la reconfiguration partielle, le floorplanning est obligatoire ; l’objectif est donc de ne pas empirer les choses. En général, on procède par essais et erreurs. La méthode la plus simple pour obtenir de bons résultats consiste toutefois à réaliser une implémentation du design sans floorplanning, puis à partir de la façon dont la logique se place naturellement. L’étape suivante consiste à organiser les zones d’une manière qui ait du sens pour la reconfiguration partielle, en utilisant le placement initial de la logique comme fil conducteur.
Dans le scénario d’usage plugin, le floorplanning peut être mis à jour au fil de l’évolution du projet. Ce n’est en revanche pas le cas dans le scénario Remote Update, c’est-à-dire lorsque la reconfiguration partielle sert à publier des mises à jour de version d’un design déjà diffusé : avec Remote Update, tous les flux partiels doivent correspondre au flux initial. En conséquence, la partie de logique statique du design est figée dès la diffusion du flux initial. Cela signifie, entre autres, que le floorplanning doit rester identique.
Ainsi, avant même de se lancer dans la reconfiguration partielle, la première tâche consiste à trouver une zone appropriée dans le FPGA pour la logique statique. Inutile d’y consacrer trop de temps : il s’agit simplement d’obtenir un point de départ pour la suite, une fois le projet scindé en deux morceaux.
Ne vous y trompez pas : le but de cette première étape n’est pas le floorplanning en soi, mais de voir comment Vivado place la logique sans contraintes, et d’en déduire quelle zone doit être allouée à la logique statique. Voici les étapes :
- Réalisez une implémentation du design comme d’habitude. Ouvrez le design implémenté et regardez la vue du circuit (Device view). Essayez de vous faire une idée de la quantité de ressources logiques consommée par le design statique et de la façon dont Vivado préfère les placer.
- Il peut être plus facile de procéder ainsi si les parties destinées à devenir de la logique reconfigurable sont temporairement retirées du projet (mais d’une manière qui n’entraîne pas la suppression de la logique statique par optimisation logique).
- Assurez-vous qu’aucun élément logique n’est sélectionné dans la vue du circuit, faites un clic droit dans la vue et choisissez « Draw Pblock ». Dessinez une région qui semble convenir pour accueillir la logique statique. N’imitez pas nécessairement le placement choisi par Vivado ; cherchez plutôt une forme qui alloue une surface minimale sans créer d’obstacles pour le placement de la logique ni pour le respect des contraintes de timing.
- Vivado ouvre alors une boîte de dialogue intitulée « Create a new Pblock ». Il peut suggérer de définir le Pblock par régions d’horloge (clock regions) ; le cas échéant, ne le faites pas. Demandez un Pblock basé sur les slices, les DSP et éventuellement d’autres éléments logiques.
- Avec les FPGA Ultrascale, la boîte de dialogue du Pblock peut aussi proposer d’inclure les IOB. Si c’est le cas, décochez cette option, sinon Vivado risque de rester bloqué plus tard lors de l’enregistrement ou du redimensionnement du Pblock (à cause d’un bug dans Vivado).
- Soyez attentif à la forme du Pblock, en particulier à la plage de slices. Ces informations se trouvent dans le panneau des propriétés du Pblock de l’interface graphique de Vivado (sous l’onglet « General ») ou dans la console Tcl, où l’on verra quelque chose comme :
startgroup create_pblock pblock_1 resize_pblock pblock_1 -add {SLICE_X108Y148:SLICE_X149Y249 DSP48_X4Y60:DSP48_X5Y99 RAMB18_X4Y60:RAMB18_X6Y99 RAMB36_X4Y30:RAMB36_X6Y49} endgroup - Si des avertissements apparaissent dans la console Tcl, ignorez-les.
- En fermant le design implémenté, Vivado demandera s’il faut l’enregistrer. Choisissez « No », car le Pblock qui vient d’être créé ne sert à rien.
Configuration d’un projet pour la reconfiguration partielle
La UG909 de Xilinx suggère deux procédures de travail pour la reconfiguration partielle :
- Le flux sans projet (non-project flow), traité dans son chapitre 3, où l’implémentation est réalisée en écrivant et en exécutant explicitement des scripts Tcl.
- Le flux par projet (project flow), traité dans son chapitre 4, qui correspond à l’utilisation de l’interface graphique de Vivado et des scripts qu’elle génère automatiquement.
Je vais utiliser ici le flux par projet, même s’il comporte quelques limitations, dont certaines concernent le type de sources du module reconfigurable (notamment pour ce qui est des block designs). Quoi qu’il en soit, mieux vaut commencer par le flux par projet, car les scripts d’implémentation qu’il génère constituent une bonne base pour le flux sans projet, si le besoin s’en fait sentir.
Voici les étapes pour activer la prise en charge de la reconfiguration partielle dans un projet existant :
- Sélectionnez Tools > Enable Dynamic Function eXchange… et cliquez sur « Convert ». L’interface graphique vous fera bien comprendre que la transformation du projet en flux de reconfiguration partielle est irréversible ; acceptez-le. La commande Tcl réellement exécutée est :
set_property PR_FLOW 1 [current_project]
- Déterminez quel est le module de plus haut niveau pour la partition reconfigurable, puis faites un clic droit sur son fichier source dans le panneau Sources du Project Manager de Vivado. Choisissez « Create Partition Definition… ». Cette option n’est disponible qu’après avoir activé DFX, ce que vous venez de faire.
- Une fenêtre « Create Partition Definition » apparaît, dans laquelle il faut indiquer deux choses. D’une part, le nom de la définition de partition (Partition Definition), qui servira à désigner l’endroit de la hiérarchie de logique où les différents modules reconfigurables peuvent être insérés. Un nom comme « pr » peut convenir. D’autre part, le nom du module reconfigurable (Reconfigurable Module Name), qui indique quelle logique va dans la partition. Par exemple, si la reconfiguration partielle sert à remplacer un filtre audio, des noms comme « lpf », « bpf » ou « hpf » sont sensés, car chaque nom dit quel filtre est appliqué. On peut aussi utiliser le nom du module de plus haut niveau, si cela aide à comprendre son rôle.
- La ligne du module choisi dans la liste Sources apparaît maintenant avec un losange jaune, accompagnée du nom du module et du nom de l’instance (par exemple « pr_block » et « pr_block_ins »), tels qu’ils sont définis dans le fichier Verilog / VHDL. Ces noms n’indiquent pas quelle logique est insérée dans la partition ; ils reflètent simplement les noms utilisés dans le HDL. La partition et le module reconfigurable se trouvent dans l’onglet « Partition Definitions » du même panneau Sources.
- Si le module reconfigurable contient des instanciations (instantiation) d’IP (par exemple une FIFO), l’IP peut être ajoutée en faisant un clic droit sur sa ligne dans les sources du projet principal (sous le panneau « Hierarchy ») et en sélectionnant « Move to configurable module… ». L’équivalent en Tcl ressemble à ceci :
move_files -of_objects [get_reconfig_modules lpf] [get_files /path/to/blkmem.xci]Cette opération déplace l’IP dans l’onglet « Partition Definitions ». - Ce n’est pas tout : l’onglet « Partition Definitions » fonctionne comme un ensemble de hiérarchies de sources pour chaque module reconfigurable. Par exemple, pour ajouter des fichiers HDL nécessaires à un module reconfigurable, cliquez sur « + » sous cet onglet.
- Une fois le module reconfigurable en place, définissez l’implémentation parente (voir le premier article pour les implémentations parente et enfant, ainsi que l’assistant) :
- Sélectionnez Tools > Dynamic Function eXchange Wizard.
- Cliquez sur Next dans la page d’accueil, puis dans la page d’édition des modules reconfigurables.
- Dans la page « Edit Configurations », cliquez sur « + » pour ajouter une configuration. Le nom config_1 proposé par défaut convient, car il n’a pas beaucoup d’importance. Par défaut, Vivado sélectionne correctement le module reconfigurable pour config_1 ; ce n’est pas une surprise, puisque c’est le seul pour l’instant.
- L’écran suivant sert à ajouter des runs de configuration : ne le faites pas (pour l’instant).
- Terminez l’assistant en cliquant sur Finish.
Si vous tentez d’implémenter le projet à ce stade, vous obtiendrez très probablement une erreur du genre « [DRC HDPR-30] Missing PBLOCK On Reconfigurable Cell: HD.RECONFIGURABLE cell 'pr_block_ins' must have PBLOCK assigned to itself or its descendant cells ». Autrement dit, le floorplanning est nécessaire.
Floorplanning.
À ce stade, le projet est configuré suffisamment pour pouvoir effectuer le floorplanning.
Avant de décomposer cette tâche en petites étapes, quelques points méritent d’être mentionnés :
- La zone du FPGA réservée à la logique statique doit être aussi petite que possible, mais sans rendre difficile le placement et le routage (place and route). Une estimation grossière de sa forme aurait dû être obtenue précédemment (voir « Préparation du floorplanning » plus haut).
- Les formes de la logique statique et de la logique reconfigurable doivent être aussi simples que possible, de préférence de simples rectangles ou d’autres formes qui ne créent pas de difficultés de routage.
- Le routage de la logique statique peut traverser les zones de logique reconfigurable, mais l’inverse n’est pas vrai dans la plupart des cas.
- Dans cette session de floorplanning, c’est la forme de la logique reconfigurable que l’on dessine. En raison des deux derniers points, c’est cette forme qu’il faut garder simple.
- Soyez conscient des possibilités et des limites du floorplanning pour votre FPGA particulier, comme expliqué en détail dans les chapitres 6 à 8 de la UG909. Par exemple, avec un FPGA de la série 7, il est probablement préférable d’aligner les limites des zones sur les frontières des régions d’horloge.
Passons maintenant aux étapes :
- Lancez la synthèse du projet (c’est-à-dire le run synth_1). La synthèse du module reconfigurable sera automatiquement effectuée comme un run hors contexte (Out-of-Context, OOC), par exemple lpf_synth_1. Les OOC sont expliqués plus en détail dans le dernier article.
- Une fois les runs terminés, ouvrez le design synthétisé (l’implémentation n’est pas possible à ce stade, car aucun Pblock n’est associé au module reconfigurable).
- Dessinez un Pblock pour la logique reconfigurable. Contrairement à l’étape de préparation, il doit être associé à la logique reconfigurable. Pour cela, assurez-vous que le panneau en haut à gauche affiche l’onglet Netlist, puis faites un clic droit sur la cellule de plus haut niveau qui doit aller dans la partition reconfigurable (par exemple « pr_block_ins »). Sélectionnez Floorplanning > Draw Pblock et dessinez une zone sur le FPGA. Les opérations dans l’interface sont celles décrites plus haut (dans « Préparation du floorplanning »). Autrement dit, la sélection se fait sur la base des slices et d’autres éléments logiques.
- Encore une fois, si l’inclusion des IOB dans le Pblock est suggérée, n’acceptez pas cette suggestion : Vivado risque de rester bloqué en traitant le Pblock plus tard.
- Ne vous fatiguez pas trop sur ce dessin : il y a de bonnes chances que vous deviez le corriger à cause des remarques de Vivado. Rappelez-vous encore une fois que le Pblock est dessiné pour la logique reconfigurable et que la logique statique occupe le reste de la surface.
- Passons maintenant au panneau Pblock Properties. Il peut être nécessaire de faire un clic droit sur le Pblock dans la vue du circuit et de sélectionner « Pblock Properties… » pour le faire apparaître.
- Sélectionnez l’onglet Properties (dans le panneau Pblock Properties).
- Pour les FPGA de la série 7 (c’est-à-dire pas les Ultrascale ni plus récents) : dans le panneau Pblock Properties, il est recommandé de définir RESET_AFTER_RECONFIG si vous souhaitez que la logique reçoive la remise à zéro interne du FPGA après le chargement du flux partiel (voir le prochain article pour en savoir plus sur la remise à zéro du module reconfigurable). Cela crée une contrainte XDC comme celle-ci :
set_property RESET_AFTER_RECONFIG true [get_pblocks pblock_pr_block_ins]
Cette contrainte remet notamment les bascules (flip-flops) à leur valeur par défaut. Notez toutefois qu’elle n’a rien à voir avec d’éventuelles remises à zéro définies dans le HDL ou ailleurs dans la logique. Notez aussi que sur les FPGA de la série 7, cette fonctionnalité exige que les limites verticales du Pblock soient alignées sur les régions d’horloge.
Sur les FPGA Ultrascale et plus récents, cette remise à zéro est toujours active. - Il y a aussi la propriété SNAPPING_MODE, qui n’est pas définie par défaut pour les FPGA de la série 7 (ce qui équivaut à OFF). Pour certains FPGA, il sera probablement nécessaire de la mettre à ROUTING ou ON (ON étant la valeur par défaut pour Ultrascale). J’y reviendrai plus loin.
- Ensuite, appuyez sur CTRL-S pour enregistrer les contraintes (ou cliquez sur l’icône de disquette dans la barre du haut). Cela ajoute quelques lignes au fichier XDC, avec quelque chose comme ceci :
create_pblock pblock_pr_block_ins add_cells_to_pblock [get_pblocks pblock_pr_block_ins] [get_cells -quiet [list pr_block_ins]] resize_pblock [get_pblocks pblock_pr_block_ins] -add {SLICE_X40Y100:SLICE_X79Y149} resize_pblock [get_pblocks pblock_pr_block_ins] -add {DSP48_X2Y40:DSP48_X2Y59} resize_pblock [get_pblocks pblock_pr_block_ins] -add {RAMB18_X2Y40:RAMB18_X2Y59} resize_pblock [get_pblocks pblock_pr_block_ins] -add {RAMB36_X2Y20:RAMB36_X2Y29} - Fermez le design synthétisé.
- Réinitialisez le run synth_1.
- Tentez de générer un flux binaire (en cliquant sur « Generate Bitstream »). Le but de cette implémentation est de vérifier si le floorplanning présente des défauts, autrement dit si Vivado émet des avertissements critiques (Critical Warnings) en réponse à de tels défauts. Cela peut sembler une façon peu professionnelle de valider le design, mais c’est pourtant simple et fiable.
Corriger le floorplanning
C’est sans doute la partie la moins agréable de la reconfiguration partielle : obtenir un floorplanning vraiment correct. Si vous travaillez pour le cas d’usage Remote Update, cette phase est encore plus importante, car ce floorplanning restera pendant toute la vie du projet.
Les corrections du floorplanning sont nécessaires pour deux raisons principales : répondre aux avertissements critiques, puis, à un stade ultérieur, optimiser l’utilisation du FPGA. L’objectif est de réduire le gaspillage de ressources tout en évitant de créer des obstacles pour le placement et le routage.
Faire des modifications n’est pas difficile : il suffit de déplacer les limites d’un Pblock à la souris. On peut aussi élargir un Pblock avec des rectangles supplémentaires : faites un clic droit sur le Pblock et sélectionnez « Add Pblock Rectangle ».
Les avertissements critiques indiquent souvent les corrections nécessaires ; il faut néanmoins avoir lu le chapitre correspondant (6, 7 ou 8) du guide utilisateur de Xilinx, UG909, au sujet des limites du floorplanning pour votre FPGA particulier.
Le reste de cette section traite des problèmes possibles avec les FPGA de la série 7. Les FPGA Ultrascale sont beaucoup plus faciles à utiliser.
Une erreur courante avec les FPGA de la série 7 est la division des colonnes de tuiles d’interconnexion (interconnect tile columns). Par exemple :
[Constraints 18-993] The Pblock pblock_pr_block_ins has defined an area that causes the splitting of interconnect tile columns. Dynamic Function eXchange requires that the left and right paired interconnect tile columns cannot be split by a reconfigurable boundary. This is caused by either the left or right edge of a Pblock boundary, or by the Pblock spanning over logic types not included in the Pblock ranges. To avoid an unroutable situation, placement will be prohibited from both of these columns. To avoid placement restrictions, modify the Pblock to avoid splitting the two columns. The column of the split contains interconnect tile INT_L_X48Y299 (SLICE_X79Y299 SLICE_X78Y299). Please refer to the Xilinx document on Dynamic Function eXchange. Resolution: Set the Pblock property SNAPPING_MODE to value of ON, or modify the column/X specification of the pblock to avoid this edge.
et
[Constraints 18-996] The split between the left and right columns occurs between a reconfigurable Pblock and Static logic. The static sites are not reconfigurable. The Pblock should be adjusted to remove the column from the Pblock, unless the excluded reconfigurable and static sites are not needed for the design. Note that adjusting the Pblock will prevent prohibits and improve placement of the design, but may reduce the routability if the removed sites were needed to span across the static logic. Failure to modify the Pblock may lead to an unplaceable design if these prohibited sites are required by the design. Resolution: Set the Pblock property SNAPPING_MODE to value of ON, or modify the column/X specification of the pblock to avoid this edge. and
Pour corriger cela, réglez la propriété SNAPPING_MODE du Pblock sur ROUTING ou ON (il y a de fortes chances que ROUTING ne suffise pas, alors choisissez ON), comme suggéré dans le premier avertissement. Cela ajoutera probablement beaucoup de contraintes au fichier XDC, du genre :
set_property PROHIBIT true [get_sites SLICE_X79Y349] set_property PROHIBIT true [get_sites SLICE_X78Y349] [ ... ] set_property PROHIBIT true [get_sites SLICE_X79Y191] set_property PROHIBIT true [get_sites SLICE_X78Y191] set_property PROHIBIT true [get_sites PMV_X0Y2] set_property PROHIBIT true [get_sites SLICE_X36Y190] set_property PROHIBIT true [get_sites SLICE_X37Y190] [ ... ] set_property PROHIBIT true [get_sites SLICE_X79Y176] set_property PROHIBIT true [get_sites SLICE_X78Y176] set_property PROHIBIT true [get_sites T14] set_property PROHIBIT true [get_sites R15] set_property PROHIBIT true [get_sites XADC_X0Y0] set_property PROHIBIT true [get_sites SLICE_X36Y175] set_property PROHIBIT true [get_sites SLICE_X37Y175] [ ... ]
et ainsi de suite.
Les contraintes PROHIBIT posées sur les sites de type slice sont celles qui font taire l’avertissement critique en question. Les autres affectations PROHIBIT sont ajoutées pour des sites logiques inclus dans la zone géométrique, mais qui ne sont pas autorisés pour la reconfiguration partielle sur le FPGA utilisé. Les FPGA Ultrascale et plus récents produisent nettement moins de lignes PROHIBIT, voire aucune.
Si le but est uniquement de faire taire l’avertissement critique, il est probablement acceptable de supprimer toutes les lignes PROHIBIT et de n’en conserver qu’une seule, uniquement pour les slices. Pour cela, couvrez la plage de slices que Vivado a ajoutée en réponse au changement de SNAPPING_MODE. Transformez donc cette plage en quelque chose comme :
set_property PROHIBIT true [get_sites -range {SLICE_X79Y0 SLICE_X79Y349}]
C’est le genre de ligne dans le fichier XDC qui peut résoudre le problème de division des colonnes d’interconnexion sans rendre le fichier énorme.
Quoi qu’il en soit, une ligne de ce type peut aussi apparaître dans le fichier XDC. La supprimer ne pose apparemment aucun problème :
set_property HD.PLATFORM_WRAPPER true [get_cells pr_block_ins]
Réduire le fichier XDC au minimum qui fait taire les avertissements critiques peut sembler un peu superficiel, mais l’alternative est un fichier de contraintes énorme, source de confusion par la suite. D’après mon expérience, l’absence d’avertissements de ce genre peut être considérée comme une validation du floorplan du design.
Il y a de fortes chances que le fait de remettre la propriété SNAPPING_MODE à OFF pose à nouveau des problèmes, quelles que soient les modifications apportées au XDC.
Ajout d’un module reconfigurable
Jusqu’ici, l’implémentation revient pratiquement à une conception hiérarchique, avec quelques restrictions supplémentaires. Même si un flux binaire partiel est généré, il est assez inutile, car le charger ne change rien au design.
Le but est donc de créer un autre flux binaire partiel, basé sur un autre module reconfigurable. Cela nécessite d’ajouter une implémentation enfant (Child Implementation).
Ayez bien en tête le premier article avant de poursuivre, en particulier la partie sur les implémentations parente et enfant, ainsi que sur l’assistant Dynamic Function eXchange. Rappelez-vous aussi, comme indiqué plus haut dans cet article, que l’onglet « Partition Definitions » contient les modules reconfigurables actuellement définis et leurs sources.
Ouvrez l’assistant Dynamic Function eXchange depuis le menu Tools et cliquez sur Next dans la fenêtre d’accueil.
Dans la fenêtre Edit Reconfigurable Modules, cliquez sur « + ». Une boîte de dialogue s’ouvre pour ajouter un module reconfigurable. La seule chose réellement intéressante dans cette boîte de dialogue est le nom du module reconfigurable (Reconfigurable Module Name) : c’est le nom qui sert à identifier la logique reconfigurable, comme expliqué plus haut.
La boîte de dialogue demande aussi d’associer ce module à une définition de partition ; de toute façon, il n’y en a qu’une (car cet article suppose qu’une seule partition est définie).
Au moins un fichier source Verilog / VHDL doit être ajouté pour continuer ; d’autres pourront être ajoutés plus tard depuis l’onglet « Partition Definitions ». Indiquer le nom du module de plus haut niveau de ce module reconfigurable ne fait pas de mal, surtout s’il n’est pas évident à partir des fichiers sources eux-mêmes.
Revenez à l’assistant et cliquez de nouveau sur Next pour arriver à la fenêtre Edit Configurations. Cliquez sur « + » et saisissez un nom de configuration. Ce nom ne sert qu’à apparaître dans la fenêtre Design Runs. Un nom comme config_2 convient parfaitement.
Une nouvelle ligne apparaît dans la liste des configurations. Modifiez le module reconfigurable dans la colonne correspondant à la partition, afin que chaque configuration ait un module reconfigurable différent.
La dernière fenêtre est Edit Configuration Runs, qui sert à affecter des runs aux configurations. Le plus simple est de supprimer tous les runs listés dans cette fenêtre (s’il y en a), puis de cliquer sur « Automatically create configuration runs ». Cela fait ce que vous feriez de toute façon à la main : créer un run parent, l’appeler « impl_1 », puis créer des runs enfant, les appeler comme vous voulez, et en faire les enfants de « impl_1 ».
L’assistant choisit une configuration pour chaque run, mais cela se change facilement. La seule chose importante est de savoir quelle configuration est associée au run parent.
Au fait, si vous supprimez tous les runs dans l’assistant, tous les runs enfant disparaissent, mais impl_1 reste.
Enfin : l’implémentation du design
Pour générer les flux binaires, cliquez simplement sur « Generate Bitstreams » dans Vivado, comme d’habitude. Comme déjà mentionné dans le premier article, deux ou trois flux binaires sont créés pour chaque configuration dans un projet de reconfiguration partielle.
Par exemple, sur un FPGA Ultrascale, les fichiers .bit peuvent être :
- theproject.bit : le fichier de flux binaire initial, contenant la logique statique et la logique reconfigurable associée à la configuration courante.
- pr_block_ins_lpf_partial.bit : le flux binaire partiel qui charge la logique reconfigurable associée à la configuration courante.
- Uniquement sur Ultrascale, il existe aussi pr_block_ins_lpf_partial_clear.bit : le flux à charger avant tout flux partiel, si la configuration courante est déjà présente dans le FPGA.
Notez que le même nombre de fichiers de flux binaire est créé pour toutes les implémentations. Autrement dit, le fichier de flux initial est aussi créé pour les implémentations enfant ; il est donc tout à fait possible de charger le FPGA avec le flux initial de l’une des implémentations enfant et de continuer à partir de là.
Pour un moyen simple de charger des flux partiels par PCIe ou USB 3.x, voir cette page.
Aucune des implémentations ne devrait présenter d’avertissements critiques ni échouer à cause de plaintes concernant le Pblock ou le floorplanning en général, puisque ces problèmes devraient déjà être résolus. Si un tel problème survenait malgré tout, il faudrait corriger le floorplanning comme expliqué plus haut.
Il arrive parfois que, lorsqu’on clique sur « Generate Bitstream » alors que seules les implémentations enfant ont été modifiées, Vivado réponde « Bitstream generation has already completed and is up-to-date. Re-run anyway? ». C’est un peu déroutant, mais cliquer sur « Yes » lancera les implémentations enfant correctement. Cette histoire d’implémentation enfant est un peu un ajout à Vivado, ce qui explique aussi pourquoi la ligne d’état pendant l’implémentation affiche par exemple « write_bitstream complete. Child running ».
Examen des résultats
Comme la reconfiguration partielle tourne beaucoup autour du placement, il est bon d’examiner les designs implémentés. Vous pouvez ouvrir une implémentation particulière en faisant un clic droit sur « Open Implemented Design », puis en survolant l’élément de menu qui affiche à nouveau « Open Implemented Design ». Sélectionnez ensuite dans la liste l’implémentation à ouvrir. Si une implémentation manque dans la liste, c’est qu’elle est probablement déjà ouverte.
Essayez de faire un clic droit sur la ligne du niveau supérieur de la logique reconfigurable dans le panneau Netlist de la vue du design implémenté, puis choisissez « Highlight Leaf cells ». Faites de même avec la logique statique, dans une autre couleur.
Dans ce même menu contextuel, il y a aussi « Show Connectivity », qui trace des lignes blanches droites entre les éléments logiques connectés. Les chemins de routage (routing paths) réels sur le FPGA sont évidemment différents, de sorte que les zones de floorplanning traversées par ces lignes n’ont aucune signification. L’observation de la connectivité peut néanmoins aider à repérer les cas où l’organisation générale d’un floorplan fait peiner les outils.
Il est tout à fait normal que certaines cellules qui semblent appartenir à la logique statique soient placées dans la zone reconfigurable, et inversement. Ce qui doit attirer l’attention, c’est une éventuelle congestion — si la logique semble trop serrée en général, ou dans une région particulière. Si possible, des modifications du floorplanning peuvent aider à atténuer ce problème.
Autre chose à examiner : la position des broches de partition (partition pins). Elles apparaissent sous forme de barres horizontales blanches dans la vue du circuit, comme sur l’image suivante (cliquez sur l’image pour l’agrandir) :
Comme indiqué dans le premier article, les broches de partition peuvent se trouver n’importe où dans la partition reconfigurable. En revanche, si elles sont éloignées des bords de la partition, cela peut indiquer que le routeur a eu du mal avec le timing pendant l’implémentation parente.
On peut aussi obtenir une liste textuelle des coordonnées des broches de partition avec cette commande Tcl (remplacez pr_block_ins par le nom de la cellule de logique reconfigurable) :
foreach s [get_pins -of [get_cells pr_block_ins]] { set partpin [get_pplocs -quiet -pins [get_pins $s]] ; puts "$s => $partpin"; }
Les coordonnées des broches de partition correspondent à la grille des CLB (et non des slices). Sur le dessin affiché, ces broches sont appelées « Cell pins ».
Certaines broches de la cellule peuvent ne pas avoir de broche de partition associée. Cela se produit lorsqu’il y a une inadéquation entre la liste des ports du module reconfigurable (et/ou la largeur des vecteurs) et son instanciation (instantiation) par le module de logique statique. Une telle inadéquation est parfaitement légale (en Verilog), mais le résultat peut être indésirable. Cette commande Tcl permet de détecter les ports inaccessibles, en particulier lorsque cela est involontaire.
Ceci termine la partie technique sur la configuration du projet Vivado. Le prochain article aborde toutefois un aspect important de la conception FPGA : comment garantir que le remplacement de la logique se déroule de manière fiable et sans à-coups.
