Passons maintenant aux descriptions comportementales. Dans ce type de descriptions, il y a plusieurs niveaux.
Nous allons ici étudier les principales descriptions :
Les objectifs de ce chapitre sont de comprendre :
Comme tout langage de description de matériel, le VHDL décrit des structures par assemblage d'instructions concurrentes dont l'ordre d'écriture n'a aucune importance, contrairement aux instructions séquentielles qui sont exécutées les unes après les autres, comme c'est la cas du C.
VHDL offre cependant la possibilité d'utiliser des instructions séquentielles, plus naturelles pour l'homme, par le biais de processus process. Les processus peuvent avoir leurs propres variables locales variable .
Les objets manipulés par les instructions concurrentes sont les signaux signal qui disposent chacun d'un échéancier de façon à effectuer une simulation d'instructions concurrentes sur une machine séquentielle (l'ordinateur).
Il existe 3 principales instructions concurrentes :
Les différentes tâches d'un programme vhdl s'exécutent en parallèle les unes des autres. Ces tâches sont appelées processus. Toutes les instructions concurrentes sont en fait des processus mais la déclaration explicite de processus par le mot clé process permet de construire sa propre instruction par le biais d'instruction séquentielles internes au processus. Un processus peut avoir des variables locales. Le fonctionnement du processus est régi par les règles suivantes :
trame : process -- le processus peut avoir une étiquette, ici "trame" -- il n'y a pas de liste de sensibilité donc il faut des "wait" pulse <= '0'; -- pulse est à 0 en début de trame for i in 0 to 9 loop -- on génère 10 impulsions larges de 2 périodes d'horloge wait until clk'event and clk='1'; pulse <= '1'; wait until clk'event and clk='1' pulse <= '0'; end loop; wait for 100 us; -- après 100 us on reprend le process donc pulse va repasser à 0 end process;
Exercice :
Ecrivez un processus permettant de générer un train d'impulsions toutes les microsecondes : pas d'impulsion, puis une impulsions de100 ns puis une impulsions de 200ns, jusqu'à 1 microseconde comme le montre la figure ci-dessous.
Afficher la réponseprocess(x,y) begin if x='1' then z<=y; else z<='0'; end if; end process; --De quelle fonction s'agit-il ? Afficher la réponse
Si ces règles ne sont pas respectées, le processus est séquentiel.
Exercices :
Pour fiabiliser le processus séquentiel , nous avons vu qu'il était fortement recommandé de fonctionner en mode synchrone, c'est à dire avec l'utiliation d'un horloge qui échantillonne le calcul. Autrement dit un processus séquentiel synchrone a une liste de sensibilité qui se réduit simplement à l'horloge. Les signaux codés dans ce processus seront donc des sorties de bascule D.
S'il est impératif d'initialiser les bascules (cas des machines à états), le reset asynchrone peut être employé. Dans ce cas il faut le rajouter dans la liste de sensibilité car il est prioritaire sur l'horloge quand il est actif. La syntaxe générique d'un bloc de logique séquentiel est donc la suivante:
process(clk, n_reset) -- begin if n_reset='0' then sortie <= (others=>'0'); -- tous les bits de sortie sont initialisés à 0 par le reset elsif clk'event and clk='1' then liste d'instructions codant "sortie" end if; end process; --
Exercice :
Les signaux sont équivalents à des variables globales assurant les communications entre processus. Ils sont équivalents à des équipotentielles si le code est synthétisable. Les signaux ne sont pas mis à jour tout de suite mais à la fin du processus avec un delta-cycle de retard par rapport au signal ayant déclenché le processus. Les signaux sont affectés avec l'instruction <= qui se dit aussi "reçoit" plutôt que "égal" car le signal va recevoir cette valeur en fin de processus avec un delta-cycle de retard.
Les variables sont locales à chaque processus et sont mises à jour immédiatement. Elles sont très utiles pour effectuer un codage séquentiel classique comme avec le langage C. Les variables sont déclarées juste avant le corps du processus et sont affectées avec l'instruction d'affectation immédiate := de façon à bien ne pas confondre avec l'instruction <= "reçoit" pour les signaux. Les variables gardent leur valeur quand le processus est terminé.
Dans l'exemple suivant, a,b,c sont des signaux et x une variable. Enfin de processus, a et b vont prendre la valeur a+1 après un delta-cycle alors que c prendre la valeur a après un delta-cycle.
process (a) variable x : std_logic; begin x := a+1; a <= a+1; b <= x; c <= a; end if; end process; --Exercice: Ecrivez un processus qui effectue la multiplication de 2 signaux a et b. Si le résultat de la multiplication dépasse le seuil c alors la sortie prend la valeur c. Afficher la réponse]
Dans les processus, il est possible d'utiliser des structures de contrôle similaires à celles du C :
L' instructions IF reposent sur le test d'une condition qui génère un booléen. Si celui ci est "TRUE" l'instruction qui suit est exécutée
Syntaxe du IF:
if condition1 then instruction; [elsif condition2 then instruction;] ... [else instruction;] end if;
Pour coder un processus combinatoire, l'utilisation du ELSE est obligatoire de façon à traiter toutes les combinaisons (sinon il y a mémorisation donc c'est da la logqiue séquentielle)
Syntaxe du CASE :
case A is when -7 => B := 10; C :='0' when -3 => B :=15; C :='0'; when others => B :=2; C :='1'; end case;
Pour coder un processus combinatoire, l'utilisation du when others est obligatoire de façon à traiter toutes les combinaisons (sinon il y a mémorisation donc c'est da la logqiue séquentielle)
L1: for i in 0 to 10 loop ... L2: loop ... L3 : while non _stop_L3 loop ... exit L2 when stop_L2; next L3 when suite_L3; if stop_L1 then exit L1; end if; end loop L3; end loop L2; end loop L1;
Exemple : la boucle loop de cet exemple permet de compter le nombre de bits à 1 d'un signal.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -- entity nb_un is port ( a : in unsigned(7 downto 0); s : out unsigned(3 downto 0) ); end entity; -- architecture rtl of nb_un is begin process(a) variable x : unsigned (3 downto 0); begin x:= (others => '0'); for i in 0 to 7 loop x := x + ('0' & a(i)); end loop; s <= x; end process; end rtl; |
Le paquetage IEEE.numeric.std permet d'avoir accès aux fonction arithmétiques sur les types vecteurs non-signés unsigned ou signés signed.
Remarquez que l'addition se fait en concaténant chaque bit avec '0' car l'opérateur + du paquetage n'opère pas sur un bit simple. |
Exercice : Ecrivez un processus calculant la parité d'un signal sur n bits.
Afficher la réponse]
Architecture avec processus | Architecture avec affectation concurrente |
architecture arc of adder is begin process(A,B,Cin) begin S <= A xor B xor Cin; |
architecture arc of adder is begin S <= A xor B xor Cin; end arc; |
Architecture avec processus | Architecture avec affectation concurrente |
architecture arc of adder is begin process(A,B,Cin) begin if A = '0' then S <= B xor Cin; elsif B = '0' then S <= not(Cin); else S <= Cin; end if; end process; end arc; |
architecture arc of adder is begin S <= B xor Cin when A = '0' else not Cin when B = '0' else Cin; |
architecture arc of MUX is begin process(SEL) begin case SEL is when 0 => sortie <= A; when 1 => sortie <= B; when 2 => sortie <= C; when others => sortie <= D; end case; end process; end arc; |
architecture arc of MUX is begin with SEL select sortie <= A when 0, B when 1, C when 2, D when others; end arc; |
VHDL permet de spécifier des délais dans les affectations.
Il existe deux types d'affectations avec délai :
assert NOW < 10 ms -- NOW est une fonction renvoyant le temps physique
report "Fin de simulation"
severity failure
IL existe 2 types de sous-programmes:
fonction | procédure | |
paramètres d'appels | non modifiable (entrées) | les sorties sont modifiables |
valeur retournée | oui | non |
syntaxe | function F(A:
unsigned(3 downto 0)) return std_logic is ... begin ... end function F; |
procedure P(A: in
unsigned(3 downto 0)) S : out std_logic ) is ... begin ... end procedure P; |
Exemples :
Fonction de calcul de minimum et maximum en procédure.
procedure MinMax( a,b : in unigned (7 downto 0);
min : out unsigned(7 downto 0);
max : out unsigned(7 downto 0)) is
begin
if (a < b) then
min <= a;
max <= b;
else
min <= b;
max <= a;
end if;
end procedure MinMax;
MinMax(x, y, z, t);
Il faut 2 fonctions min et max pour avoir léquivalent en fonction. Voici l'exemple de min :
Exercices :
function min (a,b : unsigned(7 downto 0)
return unsigned(7 downto 0) is
varaiable min : unsigned(7 downto0);
begin
if (a < b) then
min := a;
else
min := b;
end if;
return min;
endfunction
...
z := min(x, y);
Trouvez le code de la fonction comptant le nombre de bits à 1 dans un nombre de 8 bits.
Ce chapitre vous a présenté les façons de décrire la fonctionnalité des processus, c'est-à-dire leur description comportementale.
Les descriptions comportementales ne s'opposent pas aux description structurelles. Elle se complètent : on adopte une description structurelle pour séparer un bloc en sous-systèmes simples, qui eux seront décrits comportementalement.
Les processus s'exécutent en parallèle les uns des autres, mais leur déroulement interne est séquentiel. Ils peuvent utiliser la plupart des structures de contrôle du C.
Les processus always s'exécutent en boucle, et nécessitent donc un point d'arrêt pour que le temps puisse s'écouler. Il en existe trois :
L'objectif du prochain chapitre est de faire la
différence
entre les constructions synthétisables, et celles
spécifiques à la
simulation.
.