Leçon 22 sur 22

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.1Débogage par simulationObserver avant d’implanter
22.2Débogage matérielInstrumenter la carte
22.3Erreurs courantesReconnaître les symptômes
22.4Méthode de résolutionConduire un diagnostic
Étude de casCompteur commandé par boutonComparer simulation et matériel
ExercicesScénarios guidésAppliquer 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 syntaxiquepoint-virgule, end manquantCorriger avant toute autre analyse
Erreur de typesigned + std_logic_vectorRendre les conversions explicites
Erreur d’élaborationinstance, port ou générique incorrectVérifier la hiérarchie
Avertissementsignal inutilisé, latchComprendre avant d’ignorer
Erreur d’exécutionindice hors plage, assertionReproduire 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 inferredUne conservation de valeur est-elle voulue ?
Signal trimmedLe signal influence-t-il une sortie ?
Width mismatchDes bits sont-ils perdus ?
Unconnected portL’interface est-elle incomplète ?
Clock not constrainedLa fréquence demandée est-elle définie ?
Multiple driversPlusieurs 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

FSMetat, etat_suivant, conditions de transition
Compteurcompteur, enable, terminal_count
UARTetat_tx, baud_tick, index_bit, busy
RAMadresse, we, data_in, data_out
CDCsync_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

USignal non initialisé ou non réinitialisé
XConflit de pilotes ou calcul à partir d’une inconnue
ZSortie tri-state relâchée
W/L/HRé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 sourceProche du matériel synthétisé
Signaux lisiblesNoms parfois transformés
Délais idéauxDélais éventuels selon le modèle
RapidePlus 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

LED0Reset actif
LED1Horloge ou tick observé
LED2FSM non IDLE
LED3Erreur détectée
LED4..7Bits 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

ProbesSignaux internes observés
Horloge de captureDomaine d’échantillonnage
ProfondeurNombre d’échantillons stockés
TriggerCondition de démarrage
Pré-triggerHistorique avant l’événement
Post-triggerComportement 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 = 1Capturer la première défaillance
etat = ERRORObserver la transition vers l’état d’erreur
adresse = xFFIsoler une transaction précise
valid and not readyObserver un blocage d’interface
compteur = limiteVé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 incorrecteLED divisée
Fréquence inattendueMauvaise fréquence déclaréeMesure ou rapport
Fonctionnement instableHorloge logique ou bruitéeSchéma d’horloge
Timing non analysécreate_clock absentRapport 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éeBouton actif bas traité actif haut
Broche flottanteAbsence de pull-up/pull-down
Synchroniseur de reset incorrectReset local jamais relâché
Logique de resetCondition 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

BoutonActif bas ou actif haut selon la carte
LEDParfois allumée avec 0
Resetreset_n actif bas
Chip selectcs_n actif bas
Enable externeVariable 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 < 0Au moins un chemin de setup viole la contrainte
TNS < 0Somme des violations de setup
Hold violationDonnée change trop tôt après le front
Unconstrained pathsChemins 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

UARTMauvais baud ou polarité
SPICPOL/CPHA incorrect
I²CAbsence de pull-up ou sortie forcée à 1
PWMFréquence ou polarité de sortie incorrecte
RAMMode 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 LEDbitstream, broche, polarité, reset, horloge
LED toujours alluméepolarité, reset, signal constant
Compteur trop rapiderebond, niveau au lieu d’impulsion
UART illisiblebaud, niveau électrique, 8N1, masse
SPI décalémode, ordre des bits, CS
Fonctionne parfoisCDC, timing, reset, entrée asynchrone
Simulation OK, carte KOcontraintes, 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

CompilationLe code est-il accepté ?
SimulationLa fonction RTL est-elle correcte ?
SynthèseLe matériel inféré est-il attendu ?
ImplémentationLe timing est-il respecté ?
ProgrammationLe bon bitstream est-il chargé ?
CarteBroches 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 pasLe reset reste à 1 après le relâchement du bouton
L’UART est fausseLe diviseur produit 115 207 bit/s et le terminal est à 9 600
Le compteur bugLe bouton génère trois fronts après filtrage absent

 

22.4.7 Étape 7 — Choisir une observation

Hypothèse

Observation

Reset permanentLED/reset dans analyseur
Horloge absenteCompteur divisé sur LED
RebondCapture bouton_sync et bouton_filtre
TimingRapport WNS/TNS
Broche incorrecteBouclage 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ômeDescription mesurable
CauseMécanisme identifié
PreuveChronogramme, capture ou rapport
CorrectionFichiers et lignes modifiés
ValidationTests exécutés
PréventionAssertion, 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

HorlogeGénérée idéalementSource physique + contraintes
ResetStimulus contrôléBouton, RC ou contrôleur
EntréesTransitions propresBruit, rebond, asynchronisme
DélaisRTL idéauxPropagation et routage
BrochesAbstraitesAffectation et tension
ObservabilitéTous signauxInstrumentation nécessaire

 

22.4.13 Matrice hypothèses-tests

Hypothèse

Test rapide

Preuve attendue

Mauvaise polaritéInverser au topComportement cohérent
Reset actifLED resetLED reste active
Mauvais FclkMesurer PWM/tickPériode différente
RebondCapture entréePlusieurs transitions
Signal suppriméRapport/netlistAbsent après synthèse
Violation timingRapport timingSlack 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 asynchroneRisque de métastabilité
Bouton non filtréPlusieurs transitions mécaniques
Test d’un niveauIncrémentation à chaque cycle pendant l’appui
Aucune impulsion uniquePas 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 rebondissantAnalyseur logique externe ou embarqué
Bouton filtré stableProbe interne
Impulsion d’un cycleProbe ou compteur d’événements
Compteur finalLED

 

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 baudMesurer la durée d’un bit TX
Mauvais formatConfigurer le terminal en 8N1
Niveaux incompatiblesVérifier le pont USB-UART
Masse absenteRelier GND
Bits incorrectsCapturer 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, timeoutvalid=1 et ready=0 pendant trop longtemps

 

Checklist complète de débogage

Niveau

Vérifications

Compilationsyntaxe, types, ports, génériques, warnings
Simulationreset, chronogrammes, assertions, cas limites, timeout
Synthèselatches, signaux supprimés, BRAM/DSP, top-level
Contrainteshorloges, broches, I/O, CDC, chemins
TimingWNS, TNS, hold, chemins non contraints
Programmationdevice, bitstream, réussite du chargement
Cartealimentation, polarité, câblage, niveaux électriques
InstrumentationLED, ports debug, analyseur logique
Validationrépétition, régression, documentation

 

Journal de débogage recommandé

Champ

Exemple

Date/versioncommit ou archive du projet
SymptômeLED3 reste active après START
ScénarioReset, puis transmission xA5
HypothèseFSM ne quitte pas DATA_BITS
Observationindex_bit reste à 7
Causebaud_tick absent dans STOP_BIT
Correctiontransition conditionnée au tick
Teststestbench + 20 transmissions sur carte

 

Synthèse du chapitre

Notion

Résumé

Message de compilationPremier indice d’une erreur de code ou de hiérarchie.
ChronogrammeRelation temporelle entre causes et effets.
AssertionVérification automatique d’une propriété.
LED de diagnosticObservation lente d’un état ou d’une erreur.
Analyseur embarquéCapture de signaux internes à la fréquence du système.
TriggerCondition qui centre la capture sur l’événement.
Signal optimiséLogique sans effet fonctionnel supprimée.
Contrainte absenteTiming non garanti ou non analysé.
Réduction du systèmeIsolation du bloc fautif.
RégressionTest 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.