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 - Les niveaux d'abstraction dans les langages de description de matériel (HDL) - Partie 1/2
Un billet blog de f-leb

Le , par f-leb

0PARTAGES

On ne le rappellera jamais assez... Les langages de description de matériel (ou HDL pour Hardware Description Language) tels VHDL ou Verilog/SystemVerilog ne sont pas des langages de programmation classiques comme C, C++, Java, etc. Même si on retrouve des séquences procédurales dans la syntaxe de ces langages, il ne s'agit plus de produire des suites d'instructions exécutées séquentiellement par un CPU.


Le but des HDL est de générer des circuits logiques qui répondront aux spécifications, et qui seront finalement implémentés physiquement dans la puce FPGA.
Les HDL permettent à ce titre au développeur de faire des descriptions de matériel à différents niveaux d'abstraction. Les trois niveaux d'abstraction reconnus sont :
  • niveau structurel (structural) : le plus bas niveau, le circuit est vu comme des blocs de primitives ou fonctions logiques aux entrées-sorties connectées entre elles ;
  • niveau flot de données (flow data) : un niveau d'abstraction au-dessus, un signal peut être décrit par une équation logique, mais aussi avec une syntaxe un peu plus avancée parfois proche des langages procéduraux comme C ou C++ ;
  • niveau comportemental (behavorial) : le plus haut niveau d'abstraction, on ne décrit plus la structure du circuit mais comment il doit se comporter. Le langage HDL permet alors des structures de contrôle avancées avec des if... else ou des case, comme en C, C++, Java, etc. (mais on n'oublie pas la première phrase de ce billet).

Lors de la phase dite de « compilation », le synthétiseur prend en charge le programme en HDL pour générer le circuit logique d'abord, pour finalement produire le fichier binaire bitstream qui va configurer la puce FPGA cible avec le placement et le routage des composants de façon la plus optimisée possible.

À titre de démonstration, on propose de découvrir ces trois niveaux d'abstraction à travers la description d'un circuit logique combinatoire simple appelé multiplexeur (parfois appelé sélecteur) en SystemVerilog (une extension du langage Verilog).

Définition d'un multiplexeur (abrégé MUX)

L'entrée a ou b est dirigée vers la sortie s suivant la valeur du signal de sélection sel. Si sel = 0, ce sera le signal a qui sera dirigé vers la sortie s, et si sel = 1, ce sera le signal b qui sera dirigé vers la sortie s.


Schéma d'un multiplexeur

À partir de la définition, on peut établir la table de vérité d'un multiplexeur :

sel a b s
0 0 0 0
0 0 1 0
0 1 0 1
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 0
1 1 1 1
Et on en déduit l'équation logique de la sortie s : \[s = a \cdot \overline{sel} + b \cdot sel\]

Voyons quelques descriptions de ce composant logique à des niveaux d'abstraction différents.

Description structurelle

De l'équation logique, on en déduit la structure avec des portes logiques élémentaires, ici des portes AND, OR et NOT.


Schéma logique du multiplexeur

On s'aide du schéma ci-dessus pour, en SystemVerilog, instancier des portes logiques et faire du câblage :

Code SystemVerilog : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
module mux21  // multiplexeur 2 entrées - 1 sortie 
   ( 
      output   logic s, 
      input    logic a, b, sel       
   ); 
          
   logic q1, q2, sel_n;  
 
   not (sel_n, sel); 
   and (q1, a, sel_n);   
   and (q2, b, sel);    
   or  (s, q1, q2); 
   
endmodule

Faisons évoluer ce multiplexeur. Par exemple, s'il comporte maintenant quatre entrées, il faut une entrée de sélection sel codée sur 2 bits (sel[1] sel[0]).


Mais si on écrit l'équation logique à partir de la table de vérité, on se rend compte que notre multiplexeur à 4 entrées peut être obtenu en câblant astucieusement trois multiplexeurs à deux entrées :


Là encore, on se retrouve à faire du câblage, mais en réutilisant le module précédent, soit en SystemVerilog :
Code SystemVerilog : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module mux41  // 4 entrées, 1 sortie 
   ( 
      output logic s, 
      input  logic a, b, c, d, 
      input  logic [1:0] sel       
   ); 
    
   logic q1, q2; // noeuds intermédiaires 
    
   // instanciation de 3 multiplexeurs 2/1 
   mux21 U0(q1, a, c, sel[1]); 
   mux21 U1(q2, b, d, sel[1]); 
   mux21 U2(s, q1, q2, sel[0]); 
    
endmodule

Ce qui donne le schéma structurel suivant :


Et que se passe-t-il si l'on veut multiplexer des entrées de type bus ? Avec des bus de largeur 4 bits par exemple :


Les deux entrées et la sortie sont des bus 4 bits

Là encore, on s'en sort structurellement par association de 4 multiplexeurs élémentaires :
Code SystemVerilog : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module mux_bus #(parameter WIDTH = 4)   // WIDTH=4 par défaut 
   ( 
      output   logic[WIDTH-1:0] s, 
      input    logic[WIDTH-1:0] a, b, 
      input    logic sel       
   ); 
    
    
   mux21 mux_inst[WIDTH-1:0] (   // tableau d'instances de mux21 
      .s, 
      .a, 
      .b, 
      .sel   
   ); 
    
endmodule

Le module ici est même paramétré pour une largeur de bus WIDTH quelconque. Le schéma structurel devient :


Bien entendu, même en se limitant à la logique combinatoire, il est difficile de tout concevoir de cette façon pour des fonctionnalités avancées. De plus, il est difficile de modifier la structure si la fonctionnalité doit évoluer, le code est difficilement maintenable. Il faut alors programmer à un plus haut niveau d'abstraction et faire confiance au synthétiseur logique pour générer la structure.

Dans la deuxième partie de ce billet, nous verrons les derniers niveaux d'abstraction : flot de données et comportemental...

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