Fondamentaux de la syntaxe Verilog HDL pour les FPGA

Le langage Verilog HDL est couramment utilisé pour la modélisation et la simulation de systèmes numériques, en particulier dans le contexte des FPGA. Sa syntaxe comporte plusieurs éléments essentiels qui permettent de décrire avec précision le comportement d'un circuit.

Identifiants

Dans Verilog, la casse est significative : un identifiant en majuscules est différent du même identifiant en minuscules. Tous les mots-clés du langage sont en minuscules, similaires aux mots-clés en C tels que int ou while.

Valeurs logiques

Au-delà des états binaires classiques '0' et '1', Verilog introduit deux états supplémentaires pour une modélisation plus réaliste. L'état 'X' représente une valeur inconnue, souvent utilisée dans les conditions de type casex ou casez pour indiquer une indifférence. L'état 'Z' symboilse une haute impédance, où le signal n'est pas piloté ; cela est utile pour modéliser des bus tri-état.

La haute impédance 'Z' dans un FPGA signifie qu'une ligne de signal n'est activement conduite par aucun élément logique, et ne pilote rien en retour, offrant ainsi un état d'isolation.

Constantes

Verilog supporte plusieurs types de constantes. Les constantes entières peuvent être exprimées en notation base, ce qui améliore la lisibilité. Par exemple : 8'hab représente un nombre hexadécimal sur 8 bits, équivalent à 1010_1011 en binaire ; 8'd171 est un décimal sur 8 bits, également 1010_1011 en binaire ; 8'o253 est un octal sur 8 bits, et 8'b1010_1011 est directement en binaire.

Les constantes réelles acceptent la notation décimale ou scientifique, comme 13_2.18e2 qui vaut 13218. Les chaînes de caractères, délimitées par des guillemets, sont des séquences de codes ASCII 8 bits ; par exemple, "Hello World" contient 11 symboles et nécessite 11 octets de stockage.

Variables

Deux types de variables principaux existent : les types réseau (wire) qui modélisent les connexions physiques, et les types registre (reg) qui représentent des unités d'abstraction de stockage de données.

Paramètres

Les paramètres sont des constantes déclarées à l'intérieur d'un module, souvent utilisées pour définir les états d'une machine à états, la largeur de données ou les limites de compteurs. Par exemple :

parameter ETAT_REPOS = 3'b001;
parameter LARGEUR_COMPTEUR = 4'd15;
parameter MAX_COMPTEUR = 25'd24_999_999;

Ces paramètres sont locaux au module et peuvent être modifiés flexiblement, ce qui est une caractéristique importante pour la réutilisabilité.

Instructions d'affectation

Verilog propose deux types d'affectation : l'affectation non bloquante (<=) et l'affectation bloquante (=). L'exemple suivant illustre leur différence :

module bench_test;
    reg signal_a, signal_b, signal_c;
    initial begin
        signal_a = 0; signal_b = 0; signal_c = 0;
        #1 signal_a = 1; signal_b <= 2; signal_c = 3;
        #1 $display("signal_a=%b, signal_b=%b, signal_c=%b", signal_a, signal_b, signal_c);
    end
endmodule

Dans ce code, les variables sont initialisées à zéro. À la première unité de temps, signal_a reçoit immédiatement la valeur 1 via une affectation bloquante. L'affectation non bloquante pour signal_b reporte l'assignation de 2 au début de l'unité de temps suivante. L'affectation bloquante pour signal_c applique imméditaement la valeur 3. Ainsi, après ces instructions, signal_a vaut 1, signal_b vaut 2, et signal_c vaut 3.

L'affectation bloquante évalue et applique immédiatement l'expression, ce qui peut interrompre l'exécution séquentielle. L'affcetation non bloquante permet à l'exécution de continuer sans délai immédiat.

Fonctions système

Verilog intègre des fonctions système prédéfinies, principalement utilisées en simulation dans les testbenches. Par exemple :

$display  // Affiche un message avec saut de ligne
$write    // Affiche un message sans saut de ligne
$strobe   // Affiche un message avec saut de ligne, exécuté en dernier
$monitor  // Surveille les variables
$stop     // Suspend la simulation
$finish   // Termine la simulation
$renvoi   // Retourne le temps de simulation
$aleatoire // Génère une valeur aléatoire
$liremem  // Lit un fichier mémoire

Directives d'échelle de temps

La directive timescale spécifie l'unité et la précision temporelles pour la simulation, par exemple timescale 1ns/1ns indique une unité en nanosecondes et une précision d'un nanoseconde.

Dans les FPGA, l'unité et la précision temporelles contrôlent l'échelle et la granularité des délais de simulation. Pour des modules nécessitant une haute précision, on utilise des unités petites comme le picoseconde, tandis que pour des simulations à grande échelle, des unités plus larges comme la microseconde sont appropriées.

Voici un exemple de conception FPGA avec des modules de filtre numérique et de générateur de signal, démontrant l'utilisation des échelles de temps :

module filtre_numerique(
    input clk,
    input rst,
    input signed [7:0] entree_donnees,
    output signed [7:0] sortie_donnees
);
    `timescale 1ns/1ps  // Unité en nanosecondes, précision en picosecondes

    reg signed [7:0] registre_decalage [0:7];
    reg signed [7:0] donnee_courante;
    reg signed [7:0] donnee_sortie;

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            registre_decalage <= 8'b0;
            donnee_courante <= 8'b0;
            donnee_sortie <= 8'b0;
        end else begin
            donnee_courante <= registre_decalage[0];
            for (int idx = 0; idx < 7; idx = idx + 1) begin
                registre_decalage[idx] <= registre_decalage[idx + 1];
            end
            registre_decalage[7] <= entree_donnees;
            donnee_sortie <= donnee_courante + entree_donnees - donnee_courante; // Simplified filter logic
        end
    end

    assign sortie_donnees = donnee_sortie;
endmodule

module generateur_signal(
    input clk,
    output reg signed [7:0] signal_sortie
);
    `timescale 1us/1ps  // Unité en microsecondes, précision en picosecondes

    reg signed [7:0] compteur;
    reg horloge_locale;

    initial begin
        compteur = 8'hFF;
        horloge_locale = 1'b0;
    end

    always @(posedge clk) begin
        if (compteur == 8'hFF) begin
            horloge_locale <= ~horloge_locale;
            compteur <= 8'h00;
        end else begin
            compteur <= compteur + 1;
        end
    end

    assign signal_sortie = horloge_locale;
endmodule

Dans cet exemple, le filtre numérique utilise une échelle de temps en nanosecondes, tandis que le générateur de signal en microsecondes, permettant d'adapter la simulation aux besoins spécifiques de chaque module.

Étiquettes: Verilog FPGA HDL syntaxe simulation

Publié le 16 juin à 22h59