TD: Logique séquentielle synchrone

Avertissement: ce TD est l'application directe de la leçon 3.

Aller directement aux exercices en cliquant ici.

Compléments de syntaxe SystemVerilog : Description d'un comportement séquentiel synchrone

Vous avez utilisé la syntaxe always @(*) pour décrire des fonctions combinatoires dans le langage System Verilog. Dans le jargon des HDL, nous appelons cela un processus. Une description HDL d'un matériel est donc un ensemble de processus s'exécutant parallèlement. Pour décrire des bascules D et des registres (ou plus généralement tout élément synchrone sur une horloge) nous devons disposer d'une syntaxe permettant de déclencher l'évaluation d'un processus sur des événements de type transition d'un signal.

Pour cela, en System Verilog, nous pouvons utiliser le processus always @(posedge clk).

La syntaxe générale est :

   always @( évènement_déclenchant )
     action_à_réaliser ;

Une bascule D

Le code suivant décrit une bascule D sensible au front montant d'une horloge CLK:

    logic D,Q ;
    ...
    always @( posedge clk )
      Q <= D ;

Vous pouvez combiner la bascule D avec l'équation combinatoire de son entrée, le code suivant décrit une bascule D dont l'entrée est le calcul du ET entre deux signaux A et B.

    logic Q, A, B;
   
    always @( posedge clk )
      Q <= A & B;

Vous pouvez décrire un groupe de bascules D (un registre) en utilisant la notation vectorielle déjà vue précédemment. Le code suivant décrit un registre 8 bits.

    logic [7:0] Q, D;
   
    always @( posedge clk )
      Q <= D;

Pour déclarer une bascule fonctionnant sur front descendant il suffit de remplacer le mot-clef posedge par negedge.

Une bascule D avec initialisation asynchrone

Le processus always doit pouvoir être déclenché par le signal d'initialisation. De plus ce signal doit être prioritaire sur l'horloge.

La syntaxe suivante permet de coder une bascule D avec une initialisation asynchrone active à l'état bas d'un signal init,et dont l'action est de mettre à 0 la bascule.

    logic  Q, D, init;
   
    always @( posedge clk or negedge init)
      if (~init )
        Q <= 0;
      else
        Q <= D;

Vous pouvez interpréter cette syntaxe de la façon suivante:

  1. S'il y a un évènement (front montant) sur l'horloge , ou un évènement sur init (front descendant) alors il faut réévaluer le contenu de la bascule D.
  2. S'il faut réévaluer et que init == 0 alors c'est init qui a déclencé le processus (il est prioritaire sur l'horloge) et on passe donc la sortie de la bascule à 0.
  3. S'il faut réévaluer et que init == 1 alors c'est le front montant d'horloge qui a déclenché le processus et donc Q reçoit D.

Vous êtes évidemment libres de choisir:

  • l'état actif de l'initialisation :
    • posedge pour un signal actif à l'état haut (1) , associé au test if (init)
    • negedge pour un signal actif à l'état bas (0) , associé au test if (~init)
  • la valeur initiale : 0 ou 1

Généralisation des processus always

Jusqu'à maintenant, vous n'avez décrit que des processus (always @(*) ou always @(posedge clk)) n'ayant qu'une seule action à réaliser. Il est possible de regrouper plusieurs actions dans le corps d'un processus en utilisant la syntaxe suivante :

    begin
      première_action ;
      deuxième_action ;
      ...
    end

Remarque : begin et end remplacent les accolades du C..;

Exemple :

    logic [7:0] Q;
    logic [4:0] D,E;
    ...
    always@(posedge clk )
      begin
        Q[7:4] <= Q[3:0];
        Q[3:0] <= D+E ;
      end

 

EXERCICES 

  • Pour tous les exercices, on réalisera un shéma et une description SystemVerilog. Les transparents associés donnent un peu plus de détail sur la démarche à suivre.

A/  Bascule D avec enable

On veut une bascule D avec "enable"  et reset  synchrone actif à l'état "haut"

  • si le signal enable vaut 1, la bascule fonctionne normalement
  • si le signal enable vaut 0, la bascule est gelée, Q garde sa valeur même après un front montant de l'horloge.

Comment l'implémenter ?

B/ Parallélisation

Nous recevons une séquence de données data_in codées sur 1 bit. A chaque cycle d'horloge un signal en_in indique si le bit data_in est une donnée valide. Transformer cette séquence en séquences de données data_out de 4bits, accompagnée d'un signal en_out indiquant si la donnée data_out est valide.

C/ Sérialisation

Nous recevons une séquence de données data_in codées sur 4 bit. A chaque cycle d'horloge un signal en_in indique si data_in est une donnée valide. Transformer cette séquence en une séquence de données data_out de 1bit , accompagnée d'un signal en_out indiquant si la donnée data_out est valide.

Quelles contraintes temporelles doit vérifier la séquence entrante pour que le dispositif fonctionne ?

D/ Réaliser un détecteur de front montant

Dans le cours nous avons indiqué que l'horloge, signal global prédéfini, est l'unique signal pouvant être utilisé comme entrée de synchronisation sur une bascule

  • comment peut on faire pour détecter d'un cycle à l'autre de l'horloge, un signal est passé de l'état 0 à l'état 1 ?
  • comment garantir que le signal généré dure exactement un cycle  ?
  • comment modifier le montage pour détecter indifféremment un changement d'état de 0 à 1 ou de 1 à 0 ?
  • à quoi peut servir ce genre de montage ?

E/ Filtrage à moyenne glissante

Nous recevons une séquence de données codées sur 8 bits.

  • Réaliser un filtre calculant la somme des 4 derniers échantillons reçus.
  • Réaliser un filtre calculant la moyenne des 4 derniers échantillons reçus.
  • Optimiser la structure pour limiter le nombre d'additionneurs nécessaires à moins de 3.

Transparents des sujets d'exercice: Yves Mathieu