IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

FPGA - Que fait ce code Verilog/SystemVerilog ?
Un billet blog de f-leb

Le , par f-leb

0PARTAGES

En Verilog/SystemVerilog, on peut trouver ce genre de code :
Code SystemVerilog : Sélectionner tout
1
2
a <= b; 
b <= a;
Mais que fait ce code ? Il renvoie Vrai si a est inférieur ou égal à b... Non, ce n'est pas ça. Le signe <= est surement un opérateur d'affectation : je mets b dans a... puis a dans b ? C'est pour échanger les valeurs de a et b (swap? Mais ça ne peut pas fonctionner, car « normalement » pour faire l'échange, il faut passer par une variable temporaire :
Code C : Sélectionner tout
temp = a;  a = b;  b = temp;
À moins que cela fonctionne comme une sorte d'affectation simultanée (ou parallèle) comme en Python : a, b = b, a.
Il y a de l'idée, mais ce n'est pas encore cela. Car en HDL (Hardware Description Language), il n'y a pas de « variables » comme dans les langages de programmation, mais il y a une notion qui semble s'en rapprocher, celle des registres.

Voyons une démonstration avec deux registres 3 bits synchrones (out1 et out2) dont on peut charger le contenu en mettant le signal de contrôle enable à l'état haut, et que l'on peut permuter en mettant le signal de contrôle swap à l'état haut :
Code SystemVerilog : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module essai  
   ( 
      input logic clk, enable, swap, 
      input logic[2:0] in1, in2, 
      output logic[2:0] out1, out2    
   );    
      
   always_ff @(posedge clk) begin  // sensibilité au front montant de l'horloge 
 
      if (enable) begin  // si chargement des registres 
         out1 <= in1; 
         out2 <= in2; 
      end  
      else if (swap) begin // permutation des sorties 
         out2 <= out1; 
         out1 <= out2; 
      end 
       
   end 
    
endmodule

La simulation fonctionnelle ci-dessous montre un exemple avec le chargement des registres out1 et out2 avec les valeurs 3 et 5 présentées en entrée, sur le premier front montant de l'horloge clk repéré en rouge. Ces valeurs sont maintenues en sortie après ce front, comme mémorisées. On voit ensuite l'effet de la permutation des valeurs de sortie au 2è front montant repéré en rouge :


L'analyse RTL donne le schéma suivant, où j'ai mis en surbrillance le flot des transferts lorsque le signal swap est activé (swap=1, enable=0) :


swap=1, enable=0

On voit en rouge et en bleu que la sortie de chaque registre (3 bits) est dirigée vers l'entrée de l'autre registre, ce qui permet la permutation attendue des signaux en sortie.

Une fois le transfert effectué au front d'horloge, on peut voir ci-dessous le flot formant une boucle où la sortie de chaque registre est redirigée vers son entrée pour maintenir son état :


swap=0, enable=0

Alors comment bien interpréter cette écriture quelque peu déroutante ?
Code SystemVerilog : Sélectionner tout
1
2
         out2 <= out1; 
         out1 <= out2;

La sémantique de l'affectation dans les blocs always_ff

L'opérateur <= est donc bien un opérateur d'« affectation ».
  • Le signal du bus en sortie du registre évoqué à droite du signe <= porte l'état du registre à un instant présent. Et cet état est transmis à l'entrée du registre évoqué à gauche du signe <=, et sera pris en compte au front d'horloge suivant. Une ligne comme out2 <= out1; est donc une opération de transfert entre registres.
  • Il n'y a pas d'ordre d'exécution des affectations dans un bloc always_ff. Toutes les instructions d'affectation sont concurrentes et exécutées sur le même front d'horloge.
    On peut aussi bien écrire :
    Code : Sélectionner tout
    1
    2
             out2 <= out1; 
             out1 <= out2;
    ou
    Code : Sélectionner tout
    1
    2
             out1 <= out2; 
             out2 <= out1;

Ce dernier point souligné en gras est fondamental.

Mais alors... Que fait cet autre code ci-dessous ?
Code SystemVerilog : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
module quefaitcetruc 
   ( 
      input logic clk, in_serial, 
      output logic[3:0] Q  
   );    
      
   always_ff @(posedge clk) begin  // sensibilité au front montant de l'horloge 
      Q[3] <= in_serial; 
      Q[2] <= Q[3]; 
      Q[1] <= Q[2]; 
      Q[0] <= Q[1]; 
   end 
    
endmodule

Réponse :




Ce module décrit le comportement d'un registre à décalage SIPO (Serial Input - Parallel Output) :


Simulation registre à décalage 4 bits SIPO

On voit que le bit présenté sur l'entrée série (en jaune) est « décalé » dans le registre 4 bits Q à chaque front montant de l'horloge.
On utilise ce principe lorsque l'on a besoin de convertir des données série sur une entrée (in_serial) en des données présentes sur une sortie parallèle (bus Q).

Exemple en simulation :


On voit que la séquence série 1011 (bit de poids faible en premier) est disponible sur le bus Q[3]Q[2]Q[1]Q[0] au 4è front d'horloge.

Les quatre transferts avec l'opérateur <= ci-dessous sont effectifs sur le même front d'horloge pour que le décalage puisse s'opérer.
Code SystemVerilog : Sélectionner tout
1
2
3
4
      Q[3] <= in_serial; 
      Q[2] <= Q[3]; 
      Q[1] <= Q[2]; 
      Q[0] <= Q[1];

Structurellement, quatre bascules D synchrones sont chaînées comme sur le schéma ci-dessous :


Map view Quartus Pro Lite


Une erreur dans cette actualité ? Signalez-nous-la !