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(commewire,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(commewire,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.