La manipulation de matrices est un besoin courant dans les projets d'accélération matérielle, notamment pour le traitement d'images ou les réseaux de neurones. L'utilisation de tableaux à deux dimensions en Verilog permet de simplifier la gestion de ces structures de données tout en optimisant l'utilisation des ressources matérielles.
Définition et initilaisation des tableaux 2D
La syntaxe de base pour déclarer un tableau 2D en Verilog est :
reg [DATA_WIDTH-1:0] nom_tableau [LIGNES-1:0][COLONNES-1:0];
Exemple d'initialisation
Voici trois méthodes pour initialiser un tableau 2D :
- Initialisation manuelle : Idéale pour les petites matrices
- Intiialisation par boucle : Utile pour les matrices régulières
- Importation depuis un fichier : Adaptée aux données volumineuses
Optimisation des accès mémoire
Le mode d'accès aux éléments du tableau influence directement les performances. Voici deux approches :
// Accès ligne par ligne
always @(posedge clk) begin
for (int indexLigne = 0; indexLigne < LIGNES; indexLigne++) begin
for (int indexColonne = 0; indexColonne < COLONNES; indexColonne++) begin
// Traitement de la donnée
end
end
end
// Accès colonne par colonne
always @(posedge clk) begin
for (int indexColonne = 0; indexColonne < COLONNES; indexColonne++) begin
for (int indexLigne = 0; indexLigne < LIGNES; indexLigne++) begin
// Traitement de la donnée
end
end
end
Multiplication matricielle optimisée
Voici une implémentation pipelinée pour la multiplication de matrices :
module multiplicateurMatrices #(
parameter TAILLE = 8,
parameter LARGEUR_DONNEES = 16,
parameter ETAPES_PIPELINE = 3
) (
input wire clock,
input wire reset_n,
input wire [LARGEUR_DONNEES-1:0] matriceA [0:TAILLE-1][0:TAILLE-1],
input wire [LARGEUR_DONNEES-1:0] matriceB [0:TAILLE-1][0:TAILLE-1],
output reg [LARGEUR_DONNEES*2-1:0] resultat [0:TAILLE-1][0:TAILLE-1]
);
reg [LARGEUR_DONNEES-1:0] tamponA [0:ETAPES_PIPELINE-1][0:TAILLE-1][0:TAILLE-1];
reg [LARGEUR_DONNEES-1:0] tamponB [0:ETAPES_PIPELINE-1][0:TAILLE-1][0:TAILLE-1];
reg [LARGEUR_DONNEES*2-1:0] sommePartielle [0:TAILLE-1][0:TAILLE-1];
always @(posedge clock or negedge reset_n) begin
if (!reset_n) begin
// Initialisation du résultat
for (int indexLigne = 0; indexLigne < TAILLE; indexLigne++) begin
for (int indexColonne = 0; indexColonne < TAILLE; indexColonne++) begin
resultat[indexLigne][indexColonne] <= 0;
sommePartielle[indexLigne][indexColonne] <= 0;
end
end
// Initialisation des tampons
for (int etape = 0; etape < ETAPES_PIPELINE; etape++) begin
for (int indexLigne = 0; indexLigne < TAILLE; indexLigne++) begin
for (int indexColonne = 0; indexColonne < TAILLE; indexColonne++) begin
tamponA[etape][indexLigne][indexColonne] <= 0;
tamponB[etape][indexLigne][indexColonne] <= 0;
end
end
end
end else begin
// Logique de pipeline
end
end
endmodule