Préambule

Objectifs

La description structurelle d'un circuit complexe en vhdl présente de nombreux avantages :

L'objectif de ce chapitre est de voir précisément comment coder une représentation structurelle d'un circuit, autrement dit :

Plan du chapitre


Back to Top


Eléments de base

VHDL permet l'assemblage de "composants" ce qui constitue une description structurelle. Ce composant peut être appelé plusieurs fois dans un même circuit. Pour différencier ces mêmes composants, il est nécessaire de leur donner un nom d'"instance". L'appel d'un composant se dit aussi "instanciation

De façon à instancier un composant il est nécessaire de connaître  :

Il est important de noter  :

    1. Une compilation indépendante entre l'entité associée au composant et le circuit utilisant le composant.
    2. La conception descendante. Le composant peut être déclaré avant l'entité associée.

La description structurelle est  nécessaire pour simuler un circuit dont les vecteurs stimulis sont eux mêmes issus d'un modèle VHDL. Le modèle de plus haut niveau fait donc appel au circuit à tester (Device Under Test) et d'un générateur de stimulis. Ces deux objets sont instanciés dans un même circuit, généralement appelé "testbench" (mais ce n'est pas une obligation) qui est autonome : il n'aura pas d'entrées ni de sorties.

Exemple : le circuit top, servant à simuler le circuit  "module a" doit être autonome : son entité n'a pas d'entrée ni de sortie.

Module particulier sans entrées ni sorties (toplevel)

Cas particulier de la simulation : circuit "top" sans entrée ni sortie



Back to Top

Déclaration ET INSTANCIATION dES COMPOSANTS

Déclaration


Le mot clé component sert à déclarer le prototype d'interconnexion. La syntaxe est presque identique à celle de l'entité :

component AND_2
port (
a : in bit;
b : in bit;
s : out bit);
end component;


Pour créer rapidement un composant, une opération copier/coller de l'entité en enlevant le litéral "IS" suffit.

Instanciation :

L'instanciation d'un composant se fait dans le corps de l'architecture de cette façon :

 <NOM_INSTANCE>:<NOM_COMPOSANT> port map(LISTE DES CONNEXIONS);

Exemple:

entity AND_3 is
port(
e1 : in bit;
e2 : in bit;
e3 : in bit;
s : out bit
);
end entity;
--
architecture arc of AND_3 is
--
signal z : bit;
component and2
port (
a : bit;
b : bit;
s : bit);
end component;
--
begin
inst1 : and2 port map (a=>e1, b=>e2 , s=>z);
inst2 : and2 port map (z, e3, s);
end arc
Dans cet exemple , 2 instances de composant "and2" sont appelées pour créer une porte ET à 3
entrées.


L'association des ports du composants aux signaux de l'instance se fait
à l'aide de la
clause port map.


La syntaxe des associations est soit

  1. par nom où chaque broche du composant est associée à un signal : cas de inst_1
  2. positionnelle où l'ordre des signaux correspond à l'ordre des broches : cas de inst_2






 











Back
to 

GENERICITE

Déclaration

Un composant peut être générique en définissant les paramètres qui seront vus comme des constantes à chaque instance de composant. Il est ainsi possible de n'avoir qu'un seul composant  pour différentes instances ayant des paramètres différents. Dans la déclaration du composant, la clause generic sert à passer les paramètres au composant. Dans l'exemple suivant, l'entier positif N indique le nombre de bits de l'additionneur.

component ADD
generic
(
N : positive range 0 to 16
);
port
(
A: in std_logic_vector(N-1 downto 0);
B: in std_logic_vector(N-1 downto 0);
S: out std_logic_vector(N-1 downto 0)
);
end component;
Le paramètre N permet de
dimensionner la taille de l'additionneur, il est déclaré avec la clause generic

De même l'entité associée au composant doit comporter la clause generic pour déclarer le(s) paramètre(s)

entity ADD is
generic
(
N : positive range 0 to 16
);
port
(
A: in std_logic_vector(N-1 downto 0);
B: in std_logic_vector(N-1 downto 0);
S: out std_logic_vector(N-1 downto 0)
);
end entity ADD;

 

Instanciation :

L'instanciation d'un composant se fait dans le corps de l'architecture de cette façon :

architecture arc of mult is
component ADD
generic (
N : positive range 0 to 16);
port (
A: in std_logic_vector(N-1 downto 0);
B: in std_logic_vector(N-1 downto 0);
S: out std_logic_vector(N-1 downto 0));
end component;
signal OP1,OP2,S std_logic_vector(N-1 downto 0);
. . .
--
begin
inst_ADD : ADD
generic
map(N=>12);
port map(A=>OP1, B=>OP2,S=>S);
. . .
end arc;
La clause generic map
dans l'instanciation du composant ADD permet de fixer la valeur du
paramètre.



Instanciation de multiples composants

Les paramètres ne sont parfois pas suffisants pour écrire un code générique : on peut aussi vouloir instancier un nombre variable de composants (en fonction d'un paramètre, par exemple). Ceci est fait au moyen des mots-clef for generate..et if generate.
  

Exemple 1 : on veut décrire un multiplieur générique, tel que :


L'exemple ci-dessous fait appel à la clause IF GENERATE en testant le paramètre width.
Notez que :
  1. le ELSE n'existe pas (oubli de VHDL ?)  et qu'il faut refaire un 2ème IF.
  2. l'instruction IF GENERATE a besoin obligatoirement d'une étiquette

use work.pack.all; 
-- paquetage où sont déclarés les composants CLA-multplier

-- et WAL_multiplier

entity multiplier is
generic(
width
: positive :=8;);
port(
a : in signed(width-1 downto 0);
b : in signed(width-1 downto 0);
product : out (2*width-1 downto 0));
end entity;
--
architecture arc of multiplier is
--
begin
--
CLA_gen : if width < 8 generate
inst_cla : CLA_multiplier generic map (width) port map(a, b, product);
--
end generate CLA_gen;
--
WAL_gen : if width >= 8 generate
inst_wal : WAL_multiplier generic map (width) port map(a, b, product);
end generate WAL_gen;
--
end arc;

--

L'exemple ci-contre fait appel à la clause IF GENERATE en testant
le paramètre width.

Notez que :
  1. le ELSE
    n'existe pas (oubli de VHDL ?)  et qu'il
    faut refaire un 2ème IF.
  2. l'instruction IF GENERATE
    a besoin obligatoirement d'une
    étiquette


Exemple 2 : l'exemple classique de l'additionneur n bits... On utilise ici une boucle FOR GENERATE pour instancier automatiquement les différentes primitives ainsi que les noeuds les connectant entre elles. Notez qu'il n'est pas nécessaire de déclarer la variable de boucle mais que l'instruction FOR GENERATE nécessite une étiquette.

entity Nbit_adder is
generic( SIZE = 4);
port (
a,b : in unsigned(SIZE-1 downto 0);
ci : in std_logic;
sum : out unsigned(SIZE-1 downto 0);
co : out std_logic);
end entity;
--
component FA
port(A,B,Cin : in std_logic;
S, Cout : out std_logic);
end component;
--
architecture arc of Nbit_adder is
--
signal c :unsigned(SIZE downto 0);;
--
begin
--
C(0) <= Cin;
co <= C(SIZE);
--
G: for I in 0 to N-1 generate
inst: FA port map(A(I), B(I), C(I), sum(I), C(I+1));
end generate G;
--
end arc;


Back to 

LA CONFIGURATION

VHDL dispose d'un mécanisme appelé "configuration" permettant d'associer une instance de composant à un couple entité/architecture. La configuration est une unité de compilation à part, tout comme l'entité et l'architecture. Pour la plupart des outils , la configuration est optionnelle. Le lien composant/entité s'effectue généralement en imposant un nom de l'entité identique à celui du composant, et le lien entité/architecture s'effectue soit en considérant la dernière architecture compilée, soit l'outil impose une architecture unique.

La configuration est donc l'unité de compilation de plus haut niveau car elle permet l'élaboration de l'ensemble (l'édition de liens) pour pouvoir simuler. Son intérêt apparaît pour gérer des gros circuits où plusieurs architectures sont possibles pour une même entité. C'est la cas quend il existe des modèles d'abstraction différentes, ce qui est très utilisé pour les méthodes de conception "top down" . Par exemple une équipe peut avoir des modèles abstraits de tous les blocs de façon à accélérer les temps de simulation et travailler sur plusieurs architectures du bloc à concevoir.


Il existe plusieurs façons de configurer un projet :


Configuration hiérarchique

Pour chaque entité, une configuration est créée. Dans chaque configuration, la clause use configuration est utilisée pour les instances de composant de niveau inférieur.

configuration CF_AND2 of AND_2 is
for arc
end for;
end configuration CF_AND2;
La configuration est vide car l'entité AND_2 n'a pas d'instances de composant.
La configuration existe toutefois car tous les composants utilisés doivent avoir une configuration dans cette méthode.


configuration CF_AND3 of AND_3 is
for arc
for all : AND2
use configuration work.CF_AND2;
end for;
end for;
end configuration CF_AND3;

Le composant AND2 est instancié dans AND_3. A chaque instance la configuration CF_AND2 est utilisée.  

                                                                                                                                                                                  


Pour les gros circuits, il est fortement recommandé d'utiliser ce type de configuration car c'est la plus simple à maintenir.

Configuration à plat

Elle peut être unique et indique les liens entité/architecture explicitement avec la clause use entity(architecture). Elle est utilisée pour des circuits simples car il n'est pas nécessaire d'avoir des fichiers de configuration au niveau hiérarchique inférieur.

configuration CF_AND3_APLAT of AND_3 is
for arc
for i1 : AND2
use entity work.AND2(a1);
end for;
for i2 : AND2
use entity work.AND2(a2);
end for;
end for;
end configuration CF_AND3_APLAT;


Configuration immédiate

Les associations entité/architecture des composants peuvent être déclarés directement dans l'architecture avant le corps de l'architecture. Elle est réservée aux petits circuits pour des essais de différentes architectures.

architecture arc of TOP is
for all : AND2
use configuration work.CF_AND2;
end for;
for inst_block1 : compo
use entity work.ctr(arc);
end for;
begin
I1 : AND2 port map (...);
I2 : AND2 port map (...);
inst_block1 : compo port map (...);
end arc;


Instanciation de configuration

Dans ce cas , il n'est pas nécessaire de déclarer de composant et l'instanciation se fait en spécifiant le couple entité/architecture. La conception dans ce cas est nécessairement "bottom-up" et non "top-down" car il faut obligatoirement avoir concçu les entités appelées au niveau le plus haut.
architecture arc of TOP is
begin
I1 : entity work.and2(arc1) port map (...);
I2 : entity work.ctrl(arch) port map (...);
end arc;
Cette méthode ne nécessite pas de configuration. Elle est la plus simple mais peut être aussi moins adaptée aux gros circuits du fait de la conception "bottom up" uniquement.




Back to Top

exercices

Nous avons vu :

Faisons tout de suite des exemples !

Exercices:

  1. Codez un additionneur générique de 2 nombres non signés sur n bits.  Afficher la réponse
  2. Codez un registre générique de n bits.   Afficher la réponse
  3. Codez en VHDL structurel un accumulateur n bits à l'aide du registre générique et de l'additionneur générique. Afficher la réponse
  4. Ecrivez un testbench simple pour tester l'accumulateur par simulation.Afficher la réponse
  5. Compilez les circuits et simulez le tesbench avec ModelSim. Déboguez si nécessaire

 



Back to Top

En résumé

On a vu dans ce chapitre comment déclarer, instancier et relier les composants entre eux.

L'objectif du prochain chapitre est de savoir comment décrire le contenu d'un composant, son fonctionnement.

Back to Top