Recherche…


Remarques

Avant VHDL 1993, deux processus concurrents pouvaient communiquer uniquement avec des signaux. Grâce à la sémantique de simulation du langage qui met à jour les signaux uniquement entre les étapes de simulation, le résultat d'une simulation était déterministe: il ne dépendait pas de l'ordre choisi par le planificateur de simulation pour exécuter les processus.

[En fait, ce n'est pas vrai à 100%. Les processus peuvent également communiquer en utilisant une entrée / sortie de fichier. Mais si un concepteur compromettait le déterminisme en utilisant des fichiers, cela ne pouvait pas vraiment être une erreur.]

La langue était donc sûre. Sauf à dessein, il était presque impossible de concevoir des modèles VHDL non déterministes.

VHDL 1993 a introduit des variables partagées et la conception de modèles VHDL non déterministes est devenue très facile.

VHDL 2000 a introduit des types protégés et la contrainte que les variables partagées doivent être de type protégé.

Dans VHDL, les types protégés ressemblent à la plupart des concepts d'objets en langage orienté objet (OO). Ils implémentent l'encapsulation des structures de données et de leurs méthodes. Ils garantissent également l'accès exclusif et atomique à leurs membres de données. Cela n'empêche pas complètement le non-déterminisme mais, au moins, ajoute une exclusivité et une atomicité aux variables partagées.

Les types protégés sont très utiles lors de la conception de modèles VHDL de haut niveau destinés à la simulation uniquement. Ils ont plusieurs très bonnes propriétés des langages OO. Leur utilisation rend le code plus lisible, facile à entretenir et réutilisable.

Remarques:

  • Certaines chaînes d'outils de simulation, par défaut, émettent uniquement des avertissements lorsqu'une variable partagée n'est pas d'un type protégé.
  • Certains outils de synthèse ne prennent pas en charge les types protégés.
  • Certains outils de synthèse ont un support limité des variables partagées.
  • On pourrait penser que les variables partagées ne sont pas utilisables pour modéliser le matériel et doivent être réservées à l'instrumentation de code sans effets secondaires. Mais les modèles VHDL conseillés par plusieurs fournisseurs d'EDA pour modéliser le plan de mémoire des mémoires RAM (RAM) multi-ports utilisent des variables partagées. Donc, oui, les variables partagées peuvent être synthétisées dans certaines circonstances.

Un générateur pseudo-aléatoire

Les générateurs peu-aléatoires sont souvent utiles lors de la conception d'environnements de simulation. Le package VHDL suivant montre comment utiliser les types protégés pour concevoir un générateur pseudo-aléatoire de boolean , bit et bit_vector . Il peut facilement être étendu pour générer également std_ulogic_vector aléatoire, signed , unsigned . L'extendre pour générer des entiers aléatoires avec des limites arbitraires et une distribution uniforme est un peu plus compliqué mais réalisable.

La déclaration de package

Un type protégé a une déclaration où tous les accesseurs de sous-programmes publics sont déclarés. Pour notre générateur aléatoire, nous rendrons publique une procédure d'initialisation de graine et trois fonctions impures renvoyant un boolean aléatoire, un bit ou un bit_vector . Notez que les fonctions ne peuvent pas être pures car différents appels de l'un d'entre eux, avec les mêmes paramètres, peuvent renvoyer des valeurs différentes.

-- file rnd_pkg.vhd
package rnd_pkg is
    type rnd_generator is protected
        procedure init(seed: bit_vector);
        impure function get_boolean return boolean;
        impure function get_bit return bit;
        impure function get_bit_vector(size: positive) return bit_vector;
    end protected rnd_generator;
end package rnd_pkg;

Le corps du colis

Le corps de type protégé définit les structures de données internes (membres) et les corps de sous-programme. Notre générateur aléatoire est basé sur un registre à décalage à retour linéaire (LFSR) de 128 bits à quatre prises. La variable d' state stocke l'état actuel du LFSR. Un privé throw procédure déplace le LFSR chaque fois que le générateur est utilisé.

-- file rnd_pkg.vhd
package body rnd_pkg is
    type rnd_generator is protected body
        constant len: positive := 128;
        constant default_seed: bit_vector(1 to len) := X"8bf052e898d987c7c31fc71c1fc063bc";
        type tap_array is array(natural range <>) of positive range 1 to len;
        constant taps: tap_array(0 to 3) := (128, 126, 101, 99);

        variable state: bit_vector(1 to len) := default_seed;

        procedure throw(n: positive := 1) is
            variable tmp: bit;
        begin
            for i in 1 to n loop
                tmp := '1';
                for j in taps'range loop
                    tmp := tmp xnor state(taps(j));
                end loop;
                state := tmp & state(1 to len - 1);
            end loop;
        end procedure throw;

        procedure init(seed: bit_vector) is
            constant n:   natural            := seed'length;
            constant tmp: bit_vector(1 to n) := seed;
            constant m:   natural            := minimum(n, len);
        begin
            state         := (others => '0');
            state(1 to m) := tmp(1 to m);
        end procedure init;

        impure function get_boolean return boolean is
            constant res: boolean := state(len) = '1';
        begin
            throw;
            return res;
        end function get_boolean;

        impure function get_bit return bit is
            constant res: bit := state(len);
        begin
            throw;
            return res;
        end function get_bit;

        impure function get_bit_vector(size: positive) return bit_vector is
            variable res: bit_vector(1 to size);
        begin
            if size <= len then
                res := state(len + 1 - size to len);
                throw(size);
            else
                res(1 to len) := state;
                throw(len);
                res(len + 1 to size) := get_bit_vector(size - len);
            end if;
            return res;
        end function get_bit_vector;
    end protected body rnd_generator;
end package body rnd_pkg;

Le générateur aléatoire peut alors être utilisé dans un style OO comme dans:

-- file rnd_sim.vhd
use std.env.all;
use std.textio.all;
use work.rnd_pkg.all;

entity rnd_sim is
end entity rnd_sim;

architecture sim of rnd_sim is
    shared variable rnd: rnd_generator;
begin
    process
        variable l: line;
    begin
        rnd.init(X"fe39_3d9f_24bb_5bdc_a7d0_2572_cbff_0117");
        for i in 1 to 10 loop
            write(l, rnd.get_boolean);
            write(l, HT);
            write(l, rnd.get_bit);
            write(l, HT);
            write(l, rnd.get_bit_vector(10));
            writeline(output, l);
        end loop;
        finish;
    end process;
end architecture sim;
$ mkdir gh_work
$ ghdl -a --std=08 --workdir=gh_work rnd_pkg.vhd rnd_sim.vhd
$ ghdl -r --std=08 --workdir=gh_work rnd_sim
TRUE    1    0001000101
FALSE   0    1111111100
TRUE    1    0010110010
TRUE    1    0010010101
FALSE   0    0111110100
FALSE   1    1101110010
TRUE    1    1011010110
TRUE    1    0010010010
TRUE    1    1101100111
TRUE    1    0011100100
simulation finished @0ms


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow