Chapitre 22 — Débogage d’une conception FPGA
Objectif — Finalité du chapitre Mettre en œuvre une méthode de diagnostic reproductible permettant de localiser une erreur depuis la compilation jusqu’au fonctionnement sur carte FPGA. |
Objectifs pédagogiques
À la fin de ce chapitre, l’étudiant devra être capable de :
- classer une erreur selon l’étape où elle apparaît ;
- interpréter les messages d’analyse, d’élaboration et de synthèse ;
- exploiter un chronogramme pour expliquer un comportement incorrect ;
- observer des signaux internes et ajouter des assertions ciblées ;
- mettre en place des LED et sorties temporaires de diagnostic ;
- utiliser le principe d’un analyseur logique embarqué ;
- détecter une horloge absente, un reset permanent ou une polarité inversée ;
- repérer une broche mal affectée ou une contrainte temporelle absente ;
- comprendre pourquoi un signal inutilisé peut disparaître après synthèse ;
- réduire méthodiquement un système complexe ;
- comparer simulation, rapports d’implémentation et comportement matériel ;
- corriger puis valider sans introduire de régression.
Prérequis
- bancs de test et assertions ;
- cycles delta et chronogrammes ;
- synthèse et contraintes temporelles ;
- affectation des broches et programmation FPGA ;
- synchronisation des entrées asynchrones ;
- bonnes pratiques de programmation VHDL.
Organisation du chapitre
Section | Contenu | Compétence principale |
|---|---|---|
| 22.1 | Débogage par simulation | Observer avant d’implanter |
| 22.2 | Débogage matériel | Instrumenter la carte |
| 22.3 | Erreurs courantes | Reconnaître les symptômes |
| 22.4 | Méthode de résolution | Conduire un diagnostic |
| Étude de cas | Compteur commandé par bouton | Comparer simulation et matériel |
| Exercices | Scénarios guidés | Appliquer la méthode |
Principe central — Une hypothèse à la fois Modifier plusieurs blocs simultanément rend la cause réelle difficile à identifier. Chaque correction doit être petite, justifiée et suivie d’un test. |
22.1 Débogage par simulation
La simulation doit être la première ligne de diagnostic. Elle offre une visibilité complète sur les signaux internes et permet de reproduire exactement un scénario.
22.1.1 Catégories de messages
Catégorie | Exemples | Action |
|---|---|---|
| Erreur syntaxique | point-virgule, end manquant | Corriger avant toute autre analyse |
| Erreur de type | signed + std_logic_vector | Rendre les conversions explicites |
| Erreur d’élaboration | instance, port ou générique incorrect | Vérifier la hiérarchie |
| Avertissement | signal inutilisé, latch | Comprendre avant d’ignorer |
| Erreur d’exécution | indice hors plage, assertion | Reproduire le scénario |
22.1.2 Lire le premier message significatif
Une erreur initiale peut provoquer de nombreux messages secondaires. Il faut commencer par le premier message lié au fichier et à la ligne réellement fautive.
Traçabilité — Conserver le journal Archiver les commandes, versions, options et messages facilite la reproduction et la comparaison entre deux essais. |
22.1.3 Erreur de syntaxe
| Code incorrect | VHDL |
| if rising_edge(clk) then compteur <= compteur + 1 end if; |
| Correction | VHDL |
| if rising_edge(clk) then compteur <= compteur + 1; end if; |
22.1.4 Erreur de type
| Code incorrect | VHDL |
| signal a : std_logic_vector(7 downto 0); signal b : unsigned(7 downto 0); b <= a + 1; |
| Correction | VHDL |
| b <= unsigned(a) + 1; |
22.1.5 Erreur d’élaboration
| Association de port incorrecte | VHDL |
| U_COMPTEUR : entity work.compteur(rtl) port map ( clk => clk, reset => reset, enable => enable -- Le port q obligatoire est absent. ); |
Le message doit être rapproché de la déclaration exacte de l’entité instanciée.
22.1.6 Avertissements à traiter
Avertissement | Question |
|---|---|
| Latch inferred | Une conservation de valeur est-elle voulue ? |
| Signal trimmed | Le signal influence-t-il une sortie ? |
| Width mismatch | Des bits sont-ils perdus ? |
| Unconnected port | L’interface est-elle incomplète ? |
| Clock not constrained | La fréquence demandée est-elle définie ? |
| Multiple drivers | Plusieurs blocs pilotent-ils le même signal ? |
22.1.7 Analyse des chronogrammes
Un chronogramme doit être lu en reliant les événements de cause aux changements observés.
1. Identifier l’horloge et les fronts actifs.
2. Repérer le reset et sa durée.
3. Localiser le stimulus qui déclenche le problème.
4. Observer les entrées du bloc fautif.
5. Suivre les signaux intermédiaires.
6. Vérifier les sorties et les indicateurs.
7. Mesurer les latences en cycles.
8. Comparer au comportement attendu.
22.1.8 Ajouter les signaux utiles
Bloc | Signaux de diagnostic |
|---|---|
| FSM | etat, etat_suivant, conditions de transition |
| Compteur | compteur, enable, terminal_count |
| UART | etat_tx, baud_tick, index_bit, busy |
| RAM | adresse, we, data_in, data_out |
| CDC | sync_1, sync_2, impulsion_dest |
22.1.9 Vérifier les signaux internes
| Signaux exposés pour la simulation | VHDL |
| signal etat_courant : etat_t; signal etat_suivant : etat_t; signal compteur_bits : natural range 0 to 7; signal condition_fin : std_logic; |
Il n’est pas nécessaire de les ajouter aux ports. Le simulateur permet d’observer la hiérarchie interne.
22.1.10 Valeurs inconnues U et X
Valeur | Cause possible |
|---|---|
| U | Signal non initialisé ou non réinitialisé |
| X | Conflit de pilotes ou calcul à partir d’une inconnue |
| Z | Sortie tri-state relâchée |
| W/L/H | Résolution faible selon le modèle |
22.1.11 Ne pas masquer les X
| À éviter | VHDL |
| if signal_x /= '1' then -- Cette condition accepte aussi U, X, Z... end if; |
| Test explicite | VHDL |
| if signal_x = '0' then -- Cas bas valide. elsif signal_x = '1' then -- Cas haut valide. else assert false report "Valeur non logique sur signal_x" severity error; end if; |
22.1.12 Assertions fonctionnelles
| Invariant d’une FIFO | VHDL |
| assert not (write_en = '1' and full = '1') report "Ecriture demandee alors que la FIFO est pleine" severity error; |
| Exclusion mutuelle | VHDL |
| assert not (lecture = '1' and ecriture = '1') report "Lecture et ecriture simultanees interdites" severity failure; |
22.1.13 Assertions temporelles simples
| Impulsion d’un cycle | VHDL |
| process(clk) variable impulsion_precedente : std_logic := '0'; begin if rising_edge(clk) then assert not ( impulsion = '1' and impulsion_precedente = '1' ) report "Impulsion plus longue qu'un cycle" severity error; impulsion_precedente := impulsion; end if; end process; |
22.1.14 Assertion de latence
| Réponse attendue après trois cycles | VHDL |
| if demande = '1' then compte_attente := 3; end if; if compte_attente > 0 then compte_attente := compte_attente - 1; end if; if compte_attente = 1 then assert reponse = '1' report "Reponse absente apres trois cycles" severity error; end if; |
22.1.15 Reports ciblés
| Message de diagnostic | VHDL |
| report "Etat=" & etat_t'image(etat) & ", compteur=" & integer'image(compteur) severity note; |
Un bon message indique le bloc, le scénario et les valeurs déterminantes.
22.1.16 Testbench auto-vérifiant
| Comparaison à un modèle de référence | VHDL |
| resultat_attendu := (a_i + b_i) mod 256; assert unsigned(resultat) = to_unsigned(resultat_attendu, 8) report "Addition incorrecte : a=" & integer'image(a_i) & ", b=" & integer'image(b_i) severity error; |
22.1.17 Timeout
| Protection contre une FSM bloquée | VHDL |
| timeout : process begin wait for 1 ms; assert false report "Timeout : la simulation n'a pas termine" severity failure; end process; |
22.1.18 Reproduire un bug rare
- mémoriser les valeurs d’entrée ;
- fixer les graines aléatoires ;
- conserver l’instant du premier échec ;
- réduire le nombre de cycles avant l’échec ;
- transformer le scénario en test de régression.
22.1.19 Recherche par dichotomie temporelle
Dans une longue simulation, observer d’abord l’instant de la première sortie incorrecte, puis remonter progressivement vers les causes dans les cycles précédents.
22.1.20 Delta cycles
Un résultat inattendu au même instant physique peut être dû à plusieurs cycles delta. Vérifier les signaux juste avant et après les mises à jour.
| Stabilisation avant vérification | VHDL |
| entree <= '1'; wait for 0 ns; assert sortie = '1' severity error; |
Selon la profondeur combinatoire en processus successifs, plusieurs deltas peuvent être nécessaires. Un wait for 1 ns est parfois utilisé dans un banc de test, mais la cause doit rester comprise.
22.1.21 Comparaison RTL et post-synthèse
Simulation RTL | Simulation de netlist |
|---|---|
| Proche du code source | Proche du matériel synthétisé |
| Signaux lisibles | Noms parfois transformés |
| Délais idéaux | Délais éventuels selon le modèle |
| Rapide | Plus lente |
22.1.22 Procédure de simulation recommandée
1. Analyser tous les fichiers.
2. Élaborer l’entité de test.
3. Lancer un test court.
4. Corriger les assertions.
5. Inspecter les signaux internes.
6. Ajouter les cas limites.
7. Lancer la régression complète.
8. Archiver les résultats.
22.2 Débogage matériel
Lorsque la simulation est correcte mais que la carte ne fonctionne pas, il faut observer les interfaces, l’horloge, le reset et les signaux internes réellement implantés.
22.2.1 Commencer par un test minimal
| Test de vie de la carte | VHDL |
| process(clk_carte) begin if rising_edge(clk_carte) then compteur <= compteur + 1; end if; end process; led_vie <= compteur(compteur'high); |
Le clignotement confirme partiellement l’horloge, la programmation et l’affectation de la LED.
22.2.2 Limites de la LED de vie
Interprétation — Diagnostic partiel Une LED qui clignote ne prouve pas que toutes les contraintes sont correctes. Elle confirme seulement la chaîne observée. |
22.2.3 LED de diagnostic
LED | Information proposée |
|---|---|
| LED0 | Reset actif |
| LED1 | Horloge ou tick observé |
| LED2 | FSM non IDLE |
| LED3 | Erreur détectée |
| LED4..7 | Bits d’état ou compteur |
22.2.4 Réduire la fréquence pour observer
| Impulsion étirée | VHDL |
| if evenement = '1' then led_erreur <= '1'; compteur_led <= DUREE_VISIBLE; elsif compteur_led > 0 then compteur_led <= compteur_led - 1; else led_erreur <= '0'; end if; |
Une impulsion d’un cycle à 100 MHz est invisible à l’œil. Elle doit être mémorisée ou étirée.
22.2.5 Latch d’erreur de diagnostic
| Mémorisation jusqu’au reset | VHDL |
| process(clk) begin if rising_edge(clk) then if reset = '1' then erreur_memorisee <= '0'; elsif erreur_interne = '1' then erreur_memorisee <= '1'; end if; end if; end process; led_erreur <= erreur_memorisee; |
22.2.6 Sorties temporaires
Un signal interne peut être relié temporairement à une broche libre, à condition de respecter les niveaux électriques et les contraintes.
| Port de diagnostic | VHDL |
| debug_o <= tick_baud; |
Maintenance — Nettoyage Les ports temporaires doivent être identifiés et retirés après validation afin de ne pas devenir une dépendance permanente. |
22.2.7 Échantillonnage externe
- oscilloscope pour horloges, PWM et fronts électriques ;
- analyseur logique externe pour UART, SPI et I²C ;
- terminal série pour les messages UART ;
- multimètre pour niveaux continus et alimentations.
22.2.8 Analyseur logique embarqué
Un analyseur logique embarqué utilise la mémoire interne du FPGA pour capturer des signaux à la fréquence du circuit, puis transférer les échantillons à l’outil de développement.
Élément | Rôle |
|---|---|
| Probes | Signaux internes observés |
| Horloge de capture | Domaine d’échantillonnage |
| Profondeur | Nombre d’échantillons stockés |
| Trigger | Condition de démarrage |
| Pré-trigger | Historique avant l’événement |
| Post-trigger | Comportement après l’événement |
22.2.9 Signaux à capturer
- entrées et sorties du bloc suspect ;
- état courant de FSM ;
- compteurs et index ;
- valid, ready, busy, done ;
- erreur et timeout ;
- signaux synchronisés, pas uniquement l’entrée brute.
22.2.10 Limiter la largeur des probes
La profondeur de capture dépend de la mémoire disponible et du nombre total de bits observés. Capturer uniquement les signaux nécessaires.
22.2.11 Déclenchement simple
Trigger | Usage |
|---|---|
| erreur = 1 | Capturer la première défaillance |
| etat = ERROR | Observer la transition vers l’état d’erreur |
| adresse = xFF | Isoler une transaction précise |
| valid and not ready | Observer un blocage d’interface |
| compteur = limite | Vérifier un événement terminal |
22.2.12 Attribut de conservation de signal
| Exemple spécifique à certains outils | VHDL |
| attribute mark_debug : string; attribute mark_debug of etat_courant : signal is "true"; attribute mark_debug of compteur : signal is "true"; |
Le nom exact et l’effet des attributs dépendent du fabricant. Un signal peut aussi être sélectionné après synthèse dans l’outil.
22.2.13 Signal optimisé
Un signal sans effet fonctionnel peut disparaître. Pour l’observer, il doit être conservé par l’outil ou relié à une ressource de diagnostic.
| Signal sans influence | VHDL |
| signal debug_interne : std_logic; debug_interne <= a xor b; -- Aucun consommateur fonctionnel : suppression possible. |
22.2.14 Préserver sans perturber
Heisenbug matériel — Effet de l’instrumentation Ajouter des probes, des ports ou des attributs peut modifier le placement, le routage et parfois le timing. Toujours relancer l’analyse temporelle. |
22.2.15 Domaine d’horloge de capture
Une probe doit être interprétée dans son domaine. Capturer des signaux asynchrones avec une seule horloge peut manquer des impulsions ou afficher des transitions non cohérentes.
22.2.16 Capture multi-domaines
Utiliser un analyseur par domaine d’horloge ou synchroniser des indicateurs de diagnostic. Une capture multi-horloges exige une interprétation prudente.
22.2.17 Profondeur et fenêtre temporelle
| Calcul | Calcul |
| DUREE_CAPTURE = PROFONDEUR_ECHANTILLONS / FREQUENCE_CAPTURE Exemple : 4096 échantillons / 100 MHz = 40,96 microsecondes |
22.2.18 Décimation
Pour observer un phénomène lent, capturer un tick ou utiliser une condition d’enregistrement plutôt que d’échantillonner tous les cycles.
22.2.19 Compteur de diagnostic
| Comptage d’événements | VHDL |
| process(clk) begin if rising_edge(clk) then if reset = '1' then nb_erreurs <= (others => '0'); elsif erreur = '1' then nb_erreurs <= nb_erreurs + 1; end if; end if; end process; |
22.2.20 Signature de fonctionnement
Des compteurs d’événements, codes d’état et registres d’erreur permettent d’obtenir un résumé sans capturer toutes les formes d’onde.
22.2.21 UART de diagnostic
| Message d’état conceptuel | Architecture |
| -- Transmettre périodiquement : -- etat, compteur, flags, code_erreur -- sous forme hexadécimale ou ASCII. |
Une UART de diagnostic est utile si la broche et le débit sont disponibles, mais elle consomme des ressources et peut modifier le système.
22.2.22 Ordre recommandé sur carte
1. Vérifier les alimentations et le câble de programmation.
2. Confirmer le bon bitstream et la bonne cible.
3. Tester l’horloge avec une LED divisée ou un instrument.
4. Vérifier le reset.
5. Tester une entrée et une sortie simples.
6. Ajouter des indicateurs d’état.
7. Capturer les signaux internes.
8. Analyser le timing après instrumentation.
22.3 Erreurs courantes
22.3.1 Horloge incorrecte
Symptôme | Cause possible | Test |
|---|---|---|
| Aucune activité | Broche d’horloge incorrecte | LED divisée |
| Fréquence inattendue | Mauvaise fréquence déclarée | Mesure ou rapport |
| Fonctionnement instable | Horloge logique ou bruitée | Schéma d’horloge |
| Timing non analysé | create_clock absent | Rapport de timing |
22.3.2 Générateur de tick mal calculé
| Erreur classique | VHDL |
| constant DIVISEUR : positive := 50_000; -- Supposé produire 1 ms sans tenir compte de F_CLK. |
| Calcul paramétré | VHDL |
| constant DIVISEUR : positive := F_CLK_HZ / 1000; -- tick de 1 ms |
22.3.3 Reset permanent
Un reset maintenu actif empêche tout changement de l’état interne.
| LED de reset | VHDL |
| led_reset <= reset_interne; |
Cause | Exemple |
|---|---|
| Polarité inversée | Bouton actif bas traité actif haut |
| Broche flottante | Absence de pull-up/pull-down |
| Synchroniseur de reset incorrect | Reset local jamais relâché |
| Logique de reset | Condition combinatoire toujours vraie |
22.3.4 Broches mal affectées
- nom de port différent du fichier de contraintes ;
- indice de bus incorrect ;
- broche réservée ou non disponible ;
- mauvais bank ou standard électrique ;
- fichier de contraintes non ajouté au projet ;
- top-level différent de celui attendu.
22.3.5 Test de broches minimal
| Bouclage logique simple | VHDL |
| led_o <= interrupteur_i; |
Ce test isole les broches, le câblage et la polarité sans dépendre du reste du système.
22.3.6 Polarité inversée
Élément | Polarité fréquente |
|---|---|
| Bouton | Actif bas ou actif haut selon la carte |
| LED | Parfois allumée avec 0 |
| Reset | reset_n actif bas |
| Chip select | cs_n actif bas |
| Enable externe | Variable selon le composant |
22.3.7 Adaptation explicite de polarité
| Normalisation interne | VHDL |
| bouton_actif <= not bouton_n; reset_actif <= not reset_n; led_n <= not led_interne; |
La logique interne peut utiliser une convention active haut cohérente, tandis que le niveau supérieur adapte la carte.
22.3.8 Signal non synchronisé
Un bouton ou un signal externe utilisé directement peut provoquer des transitions imprévisibles, des rebonds ou une métastabilité.
| Chaîne correcte | Architecture |
| entree_async -> synchroniseur -> filtre éventuel -> détecteur de front -> logique utilisateur |
22.3.9 Contrainte temporelle absente
Sans contrainte, l’outil ne connaît pas la période à respecter. Une implémentation peut fonctionner dans un essai mais ne pas être garantie.
| Horloge primaire | Contraintes |
| create_clock -period 10.000 -name clk [get_ports clk] |
22.3.10 Mauvaise contrainte temporelle
Déclarer 100 MHz alors que la carte fournit 50 MHz fausse les calculs de diviseurs et l’analyse. La contrainte doit décrire le signal réel.
22.3.11 Slack négatif
Indicateur | Interprétation |
|---|---|
| WNS < 0 | Au moins un chemin de setup viole la contrainte |
| TNS < 0 | Somme des violations de setup |
| Hold violation | Donnée change trop tôt après le front |
| Unconstrained paths | Chemins non couverts par les contraintes |
22.3.12 Optimisation d’un signal inutilisé
Un compteur interne qui ne pilote aucune sortie observable peut être entièrement supprimé.
| Logique supprimable | VHDL |
| signal compteur_debug : unsigned(31 downto 0); process(clk) begin if rising_edge(clk) then compteur_debug <= compteur_debug + 1; end if; end process; -- Aucun usage de compteur_debug. |
22.3.13 Correction de l’observabilité
| Usage fonctionnel ou debug | VHDL |
| led_debug <= compteur_debug(25); |
En production, une sortie de diagnostic ne doit être conservée que si elle a une utilité réelle.
22.3.14 Mauvaise entité supérieure
Le projet peut synthétiser un composant de test au lieu du niveau carte. Vérifier le top-level avant chaque génération de bitstream.
22.3.15 Ancien bitstream
- génération non relancée après modification ;
- programmation d’un fichier situé dans un autre répertoire ;
- carte ou device incorrect ;
- échec de programmation non remarqué ;
- configuration volatile perdue après coupure.
22.3.16 Valeur générique incorrecte
Un anti-rebond prévu pour 50 MHz peut ajouter une durée différente si l’horloge réelle est 100 MHz.
| Paramétrage cohérent | VHDL |
| generic map ( F_CLK_HZ => 100_000_000, DUREE_REBOND_MS => 20 ) |
22.3.17 Débordement de compteur
| Plage trop courte | VHDL |
| signal compteur : natural range 0 to 999; -- Affectation possible à 1000 : erreur de simulation. |
Vérifier la valeur terminale, la plage et l’ordre du test avant l’incrément.
22.3.18 Latch involontaire
Un latch peut simuler une conservation de valeur mais créer un comportement temporel inattendu sur FPGA.
| Prévention | VHDL |
| process(all) begin sortie <= valeur_par_defaut; if condition = '1' then sortie <= valeur_active; end if; end process; |
22.3.19 CDC non traité
Un transfert entre deux horloges peut échouer rarement. Le symptôme dépend de la phase relative et peut disparaître lorsque l’analyseur est ajouté.
22.3.20 Mauvais mode d’interface
Interface | Erreur courante |
|---|---|
| UART | Mauvais baud ou polarité |
| SPI | CPOL/CPHA incorrect |
| I²C | Absence de pull-up ou sortie forcée à 1 |
| PWM | Fréquence ou polarité de sortie incorrecte |
| RAM | Mode read-during-write supposé |
22.3.21 Ressource matérielle non inférée
Une RAM décrite avec un reset de tous ses mots peut devenir un grand réseau de registres. Le rapport de synthèse révèle cette différence.
22.3.22 Tableau symptômes-causes
Symptôme | Causes prioritaires |
|---|---|
| Aucune LED | bitstream, broche, polarité, reset, horloge |
| LED toujours allumée | polarité, reset, signal constant |
| Compteur trop rapide | rebond, niveau au lieu d’impulsion |
| UART illisible | baud, niveau électrique, 8N1, masse |
| SPI décalé | mode, ordre des bits, CS |
| Fonctionne parfois | CDC, timing, reset, entrée asynchrone |
| Simulation OK, carte KO | contraintes, broches, physique, optimisation |
22.4 Méthode de résolution
Une méthode formelle évite les modifications aléatoires et permet de transformer chaque défaillance en test reproductible.
22.4.1 Étape 1 — Décrire précisément l’erreur
Question | Exemple de réponse |
|---|---|
| Quoi ? | Le compteur augmente deux fois |
| Quand ? | Lors du premier appui après reset |
| Où ? | Sur carte, pas dans le testbench initial |
| Fréquence ? | Environ une fois sur trois |
| Attendu ? | Une incrémentation par appui |
22.4.2 Étape 2 — Reproduire
- utiliser la même version du code ;
- conserver le même fichier de contraintes ;
- décrire la séquence d’actions ;
- noter l’état initial ;
- mesurer la fréquence de l’échec ;
- capturer un chronogramme ou un journal.
22.4.3 Étape 3 — Classer l’étape fautive
Étape | Question |
|---|---|
| Compilation | Le code est-il accepté ? |
| Simulation | La fonction RTL est-elle correcte ? |
| Synthèse | Le matériel inféré est-il attendu ? |
| Implémentation | Le timing est-il respecté ? |
| Programmation | Le bon bitstream est-il chargé ? |
| Carte | Broches et niveaux sont-ils corrects ? |
22.4.4 Étape 4 — Réduire le système
Remplacer temporairement les blocs complexes par des sources ou destinations simples.
| Exemple de réduction | VHDL |
| -- Remplacer l'UART par une LED : led_debug <= uart_start; -- Remplacer le capteur par un interrupteur : donnee_test <= interrupteur; -- Forcer une constante : enable_test <= '1'; |
22.4.5 Étape 5 — Vérifier chaque bloc
1. Entrées et polarités.
2. Synchronisation et filtrage.
3. FSM de contrôle.
4. Compteurs et délais.
5. Chemin de données.
6. Sorties et interfaces.
7. Contraintes et ressources.
22.4.6 Étape 6 — Construire une hypothèse
Une hypothèse doit relier un symptôme à un mécanisme vérifiable.
Hypothèse faible | Hypothèse testable |
|---|---|
| Le FPGA ne marche pas | Le reset reste à 1 après le relâchement du bouton |
| L’UART est fausse | Le diviseur produit 115 207 bit/s et le terminal est à 9 600 |
| Le compteur bug | Le bouton génère trois fronts après filtrage absent |
22.4.7 Étape 7 — Choisir une observation
Hypothèse | Observation |
|---|---|
| Reset permanent | LED/reset dans analyseur |
| Horloge absente | Compteur divisé sur LED |
| Rebond | Capture bouton_sync et bouton_filtre |
| Timing | Rapport WNS/TNS |
| Broche incorrecte | Bouclage interrupteur-vers-LED |
| Signal supprimé | Rapport de synthèse/netlist |
22.4.8 Étape 8 — Corriger minimalement
La correction doit viser la cause identifiée. Une refonte complète peut masquer le mécanisme et introduire de nouveaux défauts.
22.4.9 Étape 9 — Valider
- relancer le test qui échouait ;
- répéter plusieurs fois ;
- lancer les tests de non-régression ;
- relancer synthèse et timing ;
- retester sur carte ;
- retirer ou documenter l’instrumentation.
22.4.10 Étape 10 — Documenter
Champ | Contenu |
|---|---|
| Symptôme | Description mesurable |
| Cause | Mécanisme identifié |
| Preuve | Chronogramme, capture ou rapport |
| Correction | Fichiers et lignes modifiés |
| Validation | Tests exécutés |
| Prévention | Assertion, checklist ou test ajouté |
22.4.11 Arbre de décision simplifié
| Diagnostic | Méthode |
| Le code compile ? ├── Non : corriger syntaxe, types, hiérarchie. └── Oui La simulation échoue ? ├── Oui : chronogrammes, assertions, modèle. └── Non Le rapport de synthèse est attendu ? ├── Non : latches, ressources, signaux supprimés. └── Oui Le timing est respecté ? ├── Non : pipeline, contraintes, placement. └── Oui Vérifier bitstream, broches, polarités, horloge, reset et physique. |
22.4.12 Comparer simulation et réel
Élément | Simulation | Carte |
|---|---|---|
| Horloge | Générée idéalement | Source physique + contraintes |
| Reset | Stimulus contrôlé | Bouton, RC ou contrôleur |
| Entrées | Transitions propres | Bruit, rebond, asynchronisme |
| Délais | RTL idéaux | Propagation et routage |
| Broches | Abstraites | Affectation et tension |
| Observabilité | Tous signaux | Instrumentation nécessaire |
22.4.13 Matrice hypothèses-tests
Hypothèse | Test rapide | Preuve attendue |
|---|---|---|
| Mauvaise polarité | Inverser au top | Comportement cohérent |
| Reset actif | LED reset | LED reste active |
| Mauvais Fclk | Mesurer PWM/tick | Période différente |
| Rebond | Capture entrée | Plusieurs transitions |
| Signal supprimé | Rapport/netlist | Absent après synthèse |
| Violation timing | Rapport timing | Slack négatif |
22.4.14 Régression
Un bug corrigé doit devenir un test permanent. Cela empêche sa réapparition lors d’une évolution ultérieure.
| Assertion de non-régression | VHDL |
| -- Cas ayant provoqué l'ancien défaut. appui_avec_rebond; assert unsigned(compteur) = 1 report "Regression : plusieurs comptages par appui" severity failure; |
22.4.15 Quand arrêter le débogage
- cause comprise ;
- correction minimale appliquée ;
- test fautif réussi de manière répétée ;
- régression complète réussie ;
- timing et ressources validés ;
- documentation mise à jour.
Étude de cas — Compteur qui incrémente plusieurs fois
1. Symptôme
Sur carte, un appui bref sur un bouton incrémente parfois le compteur de deux à cinq unités. Une simulation avec un front propre donne toujours une seule incrémentation.
2. Version initiale
| Code problématique | VHDL |
| process(clk) begin if rising_edge(clk) then if bouton = '1' then compteur <= compteur + 1; end if; end if; end process; |
3. Analyse
Défaut | Effet |
|---|---|
| Entrée asynchrone | Risque de métastabilité |
| Bouton non filtré | Plusieurs transitions mécaniques |
| Test d’un niveau | Incrémentation à chaque cycle pendant l’appui |
| Aucune impulsion unique | Pas de notion d’événement |
4. Reproduction en simulation
| Stimulus avec rebonds | VHDL |
| bouton <= '1'; wait for 7 ns; bouton <= '0'; wait for 9 ns; bouton <= '1'; wait for 6 ns; bouton <= '0'; wait for 8 ns; bouton <= '1'; wait for 5 ms; bouton <= '0'; |
5. Signaux à observer
- bouton brut ;
- sorties des deux bascules de synchronisation ;
- sortie filtrée ;
- impulsion de front ;
- compteur.
6. Correction architecturale
| Chaîne de traitement | Architecture |
| bouton_async -> synchroniseur_2_ff -> anti_rebond -> detecteur_front -> impulsion_appui -> compteur |
7. Comptage corrigé
| Utilisation d’une impulsion | VHDL |
| process(clk) begin if rising_edge(clk) then if reset = '1' then compteur <= (others => '0'); elsif impulsion_appui = '1' then compteur <= compteur + 1; end if; end if; end process; |
8. Assertion
| Un seul comptage | VHDL |
| appui_avec_rebond; wait for DUREE_FILTRAGE + 5 * PERIODE_CLK; assert unsigned(compteur) = 1 report "Un appui doit produire un seul comptage" severity failure; |
9. Diagnostic matériel
Observation | Instrument |
|---|---|
| Bouton rebondissant | Analyseur logique externe ou embarqué |
| Bouton filtré stable | Probe interne |
| Impulsion d’un cycle | Probe ou compteur d’événements |
| Compteur final | LED |
10. Validation
- 100 appuis lents ;
- appuis longs ;
- appuis rapides compatibles avec le filtre ;
- relâchements avec rebonds ;
- reset pendant le repos ;
- relance de la synthèse et du timing.
Atelier de débogage guidé
Exercice 1 — LED toujours éteinte
Un compteur doit faire clignoter une LED, mais celle-ci reste éteinte. Proposer un ordre de tests.
1. Programmer une constante 1 puis 0 sur la LED.
2. Vérifier la polarité.
3. Vérifier la broche et le standard d’E/S.
4. Tester un interrupteur directement vers la LED.
5. Ajouter un compteur divisé.
6. Vérifier le reset.
7. Vérifier le top-level et le bitstream.
Exercice 2 — UART illisible
Hypothèse | Test |
|---|---|
| Mauvais baud | Mesurer la durée d’un bit TX |
| Mauvais format | Configurer le terminal en 8N1 |
| Niveaux incompatibles | Vérifier le pont USB-UART |
| Masse absente | Relier GND |
| Bits incorrects | Capturer START, données et STOP |
Exercice 3 — FSM bloquée
| Assertion de progression | VHDL |
| if etat = ATTENTE then compteur_attente <= compteur_attente + 1; else compteur_attente <= 0; end if; assert compteur_attente < TIMEOUT report "FSM bloquee dans ATTENTE" severity error; |
Exercice 4 — Signal absent après synthèse
Un signal debug existe en RTL mais n’apparaît pas dans la netlist. Expliquer pourquoi et proposer deux solutions.
- Il n’influence aucune sortie : optimisation normale.
- Le relier temporairement à une sortie de diagnostic.
- Utiliser une probe/analyseur logique ou un attribut de conservation adapté.
- Relancer timing après instrumentation.
Exercice 5 — Simulation correcte, timing en échec
Une chaîne combinatoire respecte la fonction mais présente WNS = -2,3 ns. Proposer des corrections.
- ajouter un pipeline ;
- réduire la largeur ou la profondeur logique ;
- supprimer une chaîne de priorité inutile ;
- utiliser DSP/BRAM ;
- vérifier la contrainte demandée ;
- analyser le placement et le fanout.
Exercice 6 — Reset inversé
| Adaptation au niveau supérieur | VHDL |
| reset_actif <= not reset_n; U_SYSTEME : entity work.systeme(rtl) port map ( clk => clk, reset => reset_actif, ... ); |
Exercice 7 — Capture ciblée
Choisir les probes et le trigger pour une erreur rare dans un transfert valid/ready.
Probes | Trigger |
|---|---|
| valid, ready, data, etat, timeout | valid=1 et ready=0 pendant trop longtemps |
Checklist complète de débogage
Niveau | Vérifications |
|---|---|
| Compilation | syntaxe, types, ports, génériques, warnings |
| Simulation | reset, chronogrammes, assertions, cas limites, timeout |
| Synthèse | latches, signaux supprimés, BRAM/DSP, top-level |
| Contraintes | horloges, broches, I/O, CDC, chemins |
| Timing | WNS, TNS, hold, chemins non contraints |
| Programmation | device, bitstream, réussite du chargement |
| Carte | alimentation, polarité, câblage, niveaux électriques |
| Instrumentation | LED, ports debug, analyseur logique |
| Validation | répétition, régression, documentation |
Journal de débogage recommandé
Champ | Exemple |
|---|---|
| Date/version | commit ou archive du projet |
| Symptôme | LED3 reste active après START |
| Scénario | Reset, puis transmission xA5 |
| Hypothèse | FSM ne quitte pas DATA_BITS |
| Observation | index_bit reste à 7 |
| Cause | baud_tick absent dans STOP_BIT |
| Correction | transition conditionnée au tick |
| Tests | testbench + 20 transmissions sur carte |
Synthèse du chapitre
Notion | Résumé |
|---|---|
| Message de compilation | Premier indice d’une erreur de code ou de hiérarchie. |
| Chronogramme | Relation temporelle entre causes et effets. |
| Assertion | Vérification automatique d’une propriété. |
| LED de diagnostic | Observation lente d’un état ou d’une erreur. |
| Analyseur embarqué | Capture de signaux internes à la fréquence du système. |
| Trigger | Condition qui centre la capture sur l’événement. |
| Signal optimisé | Logique sans effet fonctionnel supprimée. |
| Contrainte absente | Timing non garanti ou non analysé. |
| Réduction du système | Isolation du bloc fautif. |
| Régression | Test permanent associé à un bug corrigé. |
Autoévaluation
1. Par quel message commencer ?
Réponse : Le premier message significatif lié à la cause.
2. Que révèle U en simulation ?
Réponse : Souvent un signal non initialisé.
3. Pourquoi étirer une impulsion vers une LED ?
Réponse : Elle est trop rapide pour être vue.
4. Quel est le rôle d’un trigger ?
Réponse : Déclencher la capture sur un événement précis.
5. Pourquoi un signal debug disparaît-il ?
Réponse : Il n’influence aucune sortie et est optimisé.
6. Que signifie WNS négatif ?
Réponse : Une violation de setup existe.
7. Quelle est la première étape méthodique ?
Réponse : Décrire et reproduire l’erreur.
8. Pourquoi réduire le système ?
Réponse : Pour isoler la cause.
9. Que faire après une correction ?
Réponse : Relancer le test fautif et la régression.
10. Pourquoi documenter le bug ?
Réponse : Pour conserver la preuve, la cause et la prévention.
Exercice de consolidation
Une interface SPI fonctionne en simulation, mais le périphérique matériel renvoie toujours xFF. Établir une démarche de diagnostic.
| Correction méthodologique | Méthode |
| 1. Vérifier l'alimentation et la masse du périphérique. 2. Vérifier les broches SCLK, MOSI, MISO et CS_n. 3. Vérifier la polarité de CS_n. 4. Mesurer SCLK et confirmer sa fréquence. 5. Vérifier CPOL et CPHA dans la fiche technique. 6. Capturer CS_n, SCLK, MOSI et MISO. 7. Contrôler l'ordre MSB/LSB. 8. Vérifier que MISO n'est pas flottante. 9. Réduire le transfert à une commande simple. 10. Corriger, répéter, puis ajouter le cas au testbench. |
Suite du cours — Transition vers la suite Le dernier volet du cours peut regrouper les acquis dans un projet complet : spécification, architecture, simulation, synthèse, implantation, validation et documentation. |