Types de données et structures de tableaux en SystemVerilog

SystemVerilog (SV) introduit une variété de types de données intégrés et de structures de tableaux pour une modélisation matérielle flexible et efficace.

Types de données intégrés

Les types de données SV peuvent être classés selon plusieurs critères :

Classification par logique (4 valeurs vs 2 valeurs) :

  • Logique à 4 valeurs : integer, logic, reg, net-type (comme wire, tri). Ces types peuvent représenter les états 0, 1, X (inconnu) et Z (haute impédance).
  • Logique à 2 valeurs : byte, shortint, int, longint, bit. Ces types ne représentent que les états 0 et 1.

Classification par signe (signé vs non signé) :

  • Types signés : byte, shortint, int, longint, integer. Ils sont utilisés pour représenter des nombres avec signe.
  • Types non signés : bit, logic, reg, net-type (comme wire, tri). Ils sont utilisés pour représenter des grandeurs sans signe.

Le type logic est une nouveauté de SV. Il peut être piloté par des assignations continues, des portes logiques et des modules. Cependant, il ne peut pas être utilisé pour les bus bidirectionnels ou les situations multi-pilotes, où les types réseau comme wire sont nécessaires.

Tableaux

Tableaux à dimension fixe

La taille de ces tableaux est déterminée au moment de la compilation.

Déclaration de tableaux à dimension fixe :

```systemverilog

int tableau_lo_hi [0:15]; // Tableau de 16 entiers, indices de 0 à 15 int tableau_style_c [16]; // Également 16 entiers, indices de 0 à 15



#### Tableaux multidimensionnels :


    ```systemverilog
int	tableau_2d[0:7][0:3]; // Tableau 2D : 8 lignes, 4 colonnes
    int	tableau_2d_compact[8][4]; // Déclaration compacte
    tableau_2d[7][3] = 1;      // Assignation du dernier élément

Initialisation et assignation :

```systemverilog

int ascendant[4] = '{0, 1, 2, 3}; // Initialisation explicite int descendant[5]; descendant = '{4, 3, 2, 1, 0}; // Assignation de valeurs descendant[0:2] = '{5, 6, 7}; // Assignation partielle ascendant = '{4{8}}; // Répétition : 4 fois la valeur 8 descendant = '{0:9, 1:8, default:-1}; // Initialisation avec valeurs par défaut. Résultat : {9, 8, -1, -1, -1}



**Note :** La lecture d'un index hors limites d'un tableau renvoie la valeur par défaut du type d'élément du tableau (par exemple, X pour `logic`, 0 pour `int` ou `bit`).

#### Tableaux compactés (packed) et non compactés (unpacked) :

- **Tableau compacté :** Les dimensions sont déclarées avant l'identifiant de la variable. Ces tableaux sont traités comme un seul bloc de mémoire et sont utiles pour représenter des vetceurs contigus.
- **Tableau non compacté :** Les dimensions sont déclarées après l'identifiant de la varible. Chaque élément est stocké séparément.


    ```systemverilog
bit  [7:0]  compact_bits;	// Tableau compacté (implicitement)
    real  unpacked_reals [7:0];	// Tableau non compacté de réels
Considérations sur l'espace de stockage :
```systemverilog

bit [3][7:0] b_packed; // Tableau compacté (3*8 bits) bit [7:0] b_unpacked[3]; // Tableau non compacté (3 éléments de 8 bits) bit [3:0] [7:0] mix_array[3]; // Tableau mixte



`b_packed` occupe un seul octet (si les dimensions sont contiguës), tandis que `b_unpacked` occupe 3 octets distincts.

Si nous utilisons le type `logic` (qui nécessite 2 bits par état) pour représenter 24 bits de données :


    ```systemverilog
logic	[3][7:0]	l_packed; // 24 bits de logique = 48 bits = 6 octets
    logic	[7:0]	l_unpacked[3]; // 3 éléments de 8 bits de logique = 3 * (8*2 bits) = 48 bits = 6 octets

Les tableaux compactés de logic nécessitent 2 bits par bit logique, résultant en un stockage de 48 bits (6 octets) pour 24 bits logiques.

Exemple de module avec tableaux :
```systemverilog

// array_example module test_array ( ); bit [3:0] [7:0] reg_32; // Tableau compacté représentant 32 bits bit [7:0] mix_array[3]; // Tableau non compacté

    initial	begin
        reg_32	=	32'hdead_beef;
        
        $display ("reg_32 complet : %b", reg_32);
        $display ("Octet de poids fort de reg_32 : %h", reg_32[3]); // Accès au octet de poids fort
        $display ("Bit de poids fort de l'octet de poids fort : %b", reg_32[3][7]); // Accès au bit le plus significatif de l'octet le plus significatif
        
        mix_array[0] = 32'h0123_4567;
        mix_array[1] = mix_array[0];
        mix_array[2] = mix_array[1];
        
        // Vérification d'accès
        if (mix_array[1][3] == 8'h01)	
            $display ("Accès à mix_array[1][3]");
        
        if (mix_array[2][1][6] == 1'b1) 
            $display ("Accès à mix_array[2][1][6]");
        
        #50;
        // Initialisation d'un tableau non compacté
        mix_array = '{64, 63, 62}; 
    end
endmodule


#### Opérations de base sur les tableaux : boucles `for` et `foreach`

La fonction `$size(array)` renvoie la taille de la dimension la plus externe du tableau.


    ```systemverilog
initial	begin
        bit	[31: 0]	src[5], dst[5];
        // Utilisation de for pour initialiser src
        for (int i = 0; i < $size(src); i++) 
            src[i] = i;
        // Utilisation de foreach pour initialiser dst basé sur src
        foreach (dst[j])
            dst[j] = src[j] * 2;	
    end

La boucle foreach pour les tableaux multidimesnionnels :

```systemverilog

int md[2][3] = '{ '{0, 1, 2}, '{3, 4, 5} }; initial begin foreach (md[i, j]) $display("md[%0d][%0d] = %0d", i, j, md[i][j]); end



#### Opérations de base sur les tableaux : copie et comparaison

La copie d'arrays se fait directement avec l'opérateur `=`.

La comparaison de contenu d'arrays se fait avec `==` ou `!=`.


    ```systemverilog
bit	[31: 0]	src[5] = '{0, 1, 2, 3, 4};
    bit	[31: 0]	dst[5] = '{5, 4, 3, 2, 1};
    
    if (src == dst)	
        $display ("src est égal à dst");
    else
        $display ("src est différent de dst");
        
    dst = src;		// Copie de tableau
    src[0] = 5;		// Modification d'un élément

Tableaux dynamiques

Les tableaux dynamiques permettent d'allouer de la mémoire à l'exécution, offrant une flexibilité dans la gestion de la taille des tableaux.

Lors de la déclaration, les dimensions sont vides ([]). L'allocation se fait avec l'opérateur new[].

```systemverilog

int dyn[], d2[]; // Déclaration de tableaux dynamiques initial begin dyn = new[5]; // Allocation de 5 éléments foreach (dyn[j]) dyn[j] = j; // Initialisation

    d2 = dyn;		// Copie d'un tableau dynamique
    d2[0] = 5;		// Modification
    $display (dyn[0], d2[0]); // Affiche 0 et 5
    
    dyn = new[20](dyn); // Réallocation avec copie des 5 premiers éléments (les autres sont initialisés à 0)
    dyn = new[100];	// Réallocation à 100 éléments (les anciennes valeurs sont perdues)
    
    dyn.delete();	// Libération de la mémoire allouée
end


##### Exemple de module avec tableaux dynamiques :


    ```systemverilog
// dy_array_example
    module test_dy_array ( );
        int	dyn1[ ], dyn2[ ];		// Tableaux dynamiques
        
        initial	begin
            dyn1 = new[100];		// Allocation de 100 éléments
            foreach (dyn1[i])
                dyn1[i] = i;		// Initialisation
            
            dyn2 = new[100](dyn1);	// Copie de dyn1 dans dyn2
            dyn2[0] = 5;
            
            $display ("dyn1[0] = %2d, dyn2[0] = %2d", dyn1[0], dyn2[0]);
            
            // Redimensionnement et initialisation
            dyn1 = new[200](dyn1);
            $display ("La taille de dyn1 est %0d", dyn1.size());
            
            // Changement de taille
            dyn1 = new[50];
            $display ("La taille de dyn1 est %0d", dyn1.size());
            
            dyn1.delete; // Libération de la mémoire
            $display ("La taille de dyn1 est %0d", dyn1.size());
            
            // Copie
            dyn1 = dyn2;
            $display ("dyn1[0] = %2d, dyn2[0] = %2d", dyn1[0], dyn2[0]);
        end
    endmodule

Note sur la syntaxe A = new[M]; foreach(A[i]) A[i : cette ligne semble incomplète dans l'extrait original.

Étiquettes: SystemVerilog types de données tableaux tableaux dynamiques tableaux compactés

Publié le 29 mai à 19h49