Traditionnellement, on distingue deux types de descriptions :
Pour être utilisable dans une description structurelle, chaque composant doit lui-même avoir été décrit en VHDL sous la forme d’une entité et d’une architecture. Il faut considérer ces derniers comme un plan de fabrication qui permet de construire autant d’exemplaires de ce composant que nous en avons besoin. Comme dans les langages de programmation à objets, ces exemplaires sont appelés instances. L’opération de création de ces instances est appelée instanciation.
Cette page illustre la notion d’architecture structurelle à travers des exemples. Le détail de la syntaxe est expliqué dans la section : L’essentiel de VHDL / Instructions concurrentes / Instanciation.
Nous allons décrire un circuit capable d’afficher la valeur d’un compteur sur un afficheur 7 segments.
Il possédera une entrée horloge clk_i
, une entrée de réinitialisation reset_i
et une sortie segments_o
.
Nous partons de l’hypothèse que clk_i
a une fréquence de 100 MHz.
La valeur affichée sera mise à jour toutes les secondes, c’est-à-dire toutes les cent millions de périodes de clk_i
.
Nous proposons de construire le circuit en mettant deux compteurs en cascade pour compter respectivement les fronts d’horloge et les secondes. Nous utiliserons pour cela le circuit compteur modulo N présenté dans la section Architectures.
inc_i
vaut toujours '1'
).La description VHDL correspondante est détaillée ci-dessous.
Il s’agit d’une description structurelle qui contient deux instances
de l’entité CounterModN
avec l’architecture Behavioral
,
et une instance de SegmentDecoder
avec l’architecture TruthTable
.
entity CounterDemo is
port(
clk_i, reset_i : in std_logic;
segments_o : out std_logic_vector(0 to 6)
);
end CounterDemo;
architecture Structural of CounterDemo is
signal sec_inc : std_logic;
signal sec_value : integer range 0 to 15;
begin
div_counter_inst : entity work.CounterModN(Behavioral)
generic map(
N => 100e6
)
port map(
clk_i => clk_i,
reset_i => '0',
inc_i => '1',
value_o => open,
cycle_o => sec_inc
);
sec_counter_inst : entity work.CounterModN(Behavioral)
generic map(
N => 16
)
port map(
clk_i => clk_i,
reset_i => reset_i,
inc_i => sec_inc,
value_o => sec_value,
cycle_o => open
);
decoder_inst : entity work.SegmentDecoder(TruthTable)
port map(
digit_i => sec_value,
segments_o => segments_o
);
end Structural;
Le corps de cette architecture contient trois instructions d’instanciation. Examinons les éléments qui composent ces instructions.
div_counter_inst : entity work.CounterModN(Behavioral)
signifie :
div_counter_inst
est une instance de l’entitéCounterModN
et de son architectureBehavioral
qui se trouvent dans la bibliothèque de travailwork
.
La clause generic map
associe une valeur à chaque paramètre
générique de l’instance.
Cette valeur doit être une constante.
Pour l’instance div_counter_inst
, les lignes ci-dessous associent
la valeur 100e6 (100 000 000) au paramètre N
:
generic map(
N => 100e6
)
La clause port map
établit des connexions entre les ports de l’instance et
les signaux disponibles dans son environnement.
Pour l’instance div_counter_inst
les lignes ci-dessous signifient :
clk_i
de div_counter_inst
est relié au port clk_i
de CounterDemo
.reset_i
de div_counter_inst
est toujours à '0'
.inc_i
de div_counter_inst
est toujours à '1'
.value_o
de div_counter_inst
n’est pas connecté.cycle_o
de div_counter_inst
est relié au signal sec_inc
de l’architecture Structural
.port map(
clk_i => clk_i,
reset_i => '0',
inc_i => '1',
value_o => open,
cycle_o => sec_inc
);
Dans les clauses port map
et generic map
, les flèches sont toujours dirigées
vers la droite :
à gauche de la flèche, on trouve le nom d’un paramètre ou d’un port de l’entité
à instancier ;
à droite de la flèche, on trouve la valeur ou le nom du signal auquel il est associé.
Les signaux sec_inc
et sec_value
sont déclarés dans l’architecture Structural
.
signal sec_inc : std_logic;
signal sec_value : integer range 0 to 15;
Ce ne sont ni des entrées, ni des sorties. Ces signaux servent à relier entre eux les trois composants de notre circuit :
cycle_o
de div_counter_inst
est reliée à l’entrée inc_i
de sec_counter_inst
par l’intermédiaire du signal sec_inc
.value_o
de sec_counter_inst
est reliée à l’entrée digit_i
de decoder_inst
par l’intermédiaire du signal sec_value
.div_counter_inst : entity work.CounterModN(Behavioral)
...
port map(
...
cycle_o => sec_inc
);
sec_counter_inst : entity work.CounterModN(Behavioral)
...
port map(
...
inc_i => sec_inc,
value_o => sec_value,
...
);
decoder_inst : entity work.SegmentDecoder(TruthTable)
port map(
digit_i => sec_value,
...
);
La distinction entre les descriptions structurelles et comportementales est là pour faciliter la compréhension des notions et leur mise en application. En réalité, VHDL n’impose pas de respecter strictement ces deux types de description. Dans une même architecture, il est possible de mélanger des instructions comportementales et des instructions d’instanciation.
Cependant, un usage fréquent consiste à utiliser le nom Behavioral
pour les architectures
à dominante comportementale, et Structural
pour les architectures à dominante structurelle.