Composants & Instanciation

Concevoir des architectures structurelles en VHDL : déclaration de composants, port map, generic map, et instanciation directe.

Conception structurelle

En VHDL, il existe deux grandes façons de décrire un circuit :

StyleDescription
Comportemental (RTL)On décrit ce que fait le circuit (process, affectations)
StructurelOn assemble des composants existants comme sur un schéma

Le style structurel est indispensable pour organiser les grands designs en blocs hiérarchiques. Un top-level connecte des composants (UART, ALU, FIFO…) via des signaux internes.


Déclaration de composant (component)

Avant d'instancier un composant, il faut déclarer son interface dans la zone architecturale :

architecture rtl of top_level is
 
  -- Déclaration du composant (copie de l'entité)
  component additionneur is
    generic (
      g_WIDTH : integer := 8
    );
    port (
      i_a    : in  std_logic_vector(g_WIDTH-1 downto 0);
      i_b    : in  std_logic_vector(g_WIDTH-1 downto 0);
      o_sum  : out std_logic_vector(g_WIDTH-1 downto 0);
      o_cout : out std_logic
    );
  end component additionneur;
 
  -- Signaux de connexion
  signal w_result : std_logic_vector(7 downto 0);
  signal w_carry  : std_logic;
 
begin
  -- Instanciation
  U_ADD : additionneur
    generic map (g_WIDTH => 8)
    port map (
      i_a    => i_operande_a,
      i_b    => i_operande_b,
      o_sum  => w_result,
      o_cout => w_carry
    );
 
end architecture rtl;

La convention veut que les instances soient préfixées U_ (Unit) ou numérotées U1, U2.


Instanciation directe (VHDL-93)

La méthode moderne sans component — directement depuis l'entité :

architecture rtl of top_level is
  signal w_sum   : std_logic_vector(7 downto 0);
  signal w_carry : std_logic;
begin
 
  U_ADD : entity work.additionneur
    generic map (g_WIDTH => 8)
    port map (
      i_a    => i_op_a,
      i_b    => i_op_b,
      o_sum  => w_sum,
      o_cout => w_carry
    );
 
end architecture rtl;

work désigne la bibliothèque de travail courante — celle qui contient vos fichiers du projet.


Association nommée vs positionnelle

-- Association nommée (recommandée — explicite et sûre)
port map (
  i_clk   => i_clk,
  i_rst   => i_reset,
  o_data  => w_data_out
);
 
-- Association positionnelle (déconseillée — fragile)
port map (i_clk, i_reset, w_data_out);

Toujours utiliser l'association nommée. L'association positionnelle casse si l'ordre des ports change dans l'entité.


Port open — sortie non connectée

Si une sortie d'un composant n'est pas utilisée, on la laisse explicitement open :

U_CPT : entity work.compteur
  port map (
    i_clk    => i_clk,
    i_rst    => i_rst,
    o_count  => w_count,
    o_tc     => open     -- Terminal Count non utilisé
  );

open est interdit sur les entrées — une entrée doit toujours être connectée à un signal ou une valeur ('0', '1', etc.).


Exemple complet : top-level structurel

Voici un top-level qui connecte un compteur BCD à un décodeur 7 segments :

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity top_afficheur is
  port (
    i_clk   : in  std_logic;
    i_rst   : in  std_logic;
    o_seg   : out std_logic_vector(6 downto 0)
  );
end entity top_afficheur;
 
architecture structural of top_afficheur is
 
  signal w_bcd : std_logic_vector(3 downto 0);
 
begin
 
  -- Compteur BCD : compte de 0 à 9
  U_CPT : entity work.bcd_counter
    port map (
      i_clk   => i_clk,
      i_rst   => i_rst,
      i_en    => '1',
      o_count => w_bcd,
      o_tc    => open
    );
 
  -- Décodeur 7 segments : BCD → afficheur
  U_DEC : entity work.decodeur_7seg
    port map (
      i_bcd => w_bcd,
      o_seg => o_seg
    );
 
end architecture structural;

La valeur BCD transite via le signal interne w_bcdles composants ne se connectent jamais directement, ils passent par des signaux.


Plusieurs instances du même composant

Un composant peut être instancié plusieurs fois. Exemple : 4 bascules D formant un registre à décalage :

architecture structural of shift_reg_4 is
  signal w_chain : std_logic_vector(4 downto 0);
begin
 
  w_chain(0) <= i_data;
 
  GEN_FF : for i in 0 to 3 generate
    U_FF : entity work.bascule_d
      port map (
        i_clk => i_clk,
        i_rst => i_rst,
        i_d   => w_chain(i),
        o_q   => w_chain(i+1)
      );
  end generate GEN_FF;
 
  o_data <= w_chain(4);
 
end architecture structural;

L'instruction generate crée N instances automatiquement — indispensable pour les structures régulières (tableaux de registres, matrices).


Mixte : structurel + comportemental

Les deux styles peuvent coexister dans la même architecture :

architecture rtl of exemple_mixte is
  signal w_count : unsigned(7 downto 0);
  signal w_done  : std_logic;
begin
 
  -- Bloc comportemental (process)
  p_ctrl : process(i_clk)
  begin
    if rising_edge(i_clk) then
      if w_done = '1' then
        o_led <= '1';
      end if;
    end if;
  end process p_ctrl;
 
  -- Bloc structurel (instanciation)
  U_CPT : entity work.compteur_8bit
    port map (
      i_clk   => i_clk,
      i_rst   => i_rst,
      o_count => w_count,
      o_tc    => w_done
    );
 
end architecture rtl;

Résumé

ConceptSyntaxe
Instanciation directeU_X : entity work.nom
Avec génériquegeneric map (g_PARAM => valeur)
Connexion des portsport map (port => signal)
Sortie non utiliséeo_port => open
Plusieurs instancesBoucle generate

Règle d'or : le top-level ne contient que des instanciations et des signaux de connexion — toute logique métier est dans les sous-composants.