vhdl
Types protégés
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