Les Process

Le bloc process : liste de sensibilité, instructions séquentielles, et patterns combinatoire/séquentiel.

Qu'est-ce qu'un process ?

Le process est le seul endroit en VHDL où les instructions s'exécutent séquentiellement (comme dans un langage de programmation classique).

-- Structure générale
process(liste_de_sensibilite)
  -- déclarations locales (variables)
begin
  -- instructions séquentielles
end process;

Un process est un bloc concurrent par rapport au reste de l'architecture : plusieurs process s'exécutent en parallèle entre eux, mais les instructions internes à un process sont séquentielles.


La liste de sensibilité

Le process se "réveille" uniquement quand un signal de sa liste de sensibilité change.

Process combinatoire

-- Tous les signaux lus dans le process doivent être dans la liste
process(i_a, i_b, i_sel)
begin
  if i_sel = '0' then
    w_mux <= i_a;
  else
    w_mux <= i_b;
  end if;
end process;

Si un signal est oublié dans la liste de sensibilité d'un process combinatoire, la simulation sera incorrecte (mémoire implicite). La synthèse peut lever un avertissement.

Process séquentiel

-- Uniquement l'horloge (et le reset asynchrone si utilisé)
process(i_clk)
begin
  if rising_edge(i_clk) then
    r_q <= i_d;
  end if;
end process;

VHDL-2008 : process(all)

-- Capture automatiquement tous les signaux lus
process(all)
begin
  w_result <= i_a + i_b;
end process;

Pattern combinatoire

architecture rtl of alu is
  signal w_result : std_logic_vector(7 downto 0);
begin
 
  p_alu : process(i_op, i_a, i_b)
  begin
    case i_op is
      when "00" => w_result <= i_a AND i_b;
      when "01" => w_result <= i_a OR  i_b;
      when "10" => w_result <= i_a XOR i_b;
      when others => w_result <= (others => '0');
    end case;
  end process p_alu;
 
  o_result <= w_result;
 
end architecture rtl;

Notez le label de process (p_alu :) — bonne pratique pour la lisibilité.


Pattern séquentiel (registre + reset synchrone)

p_reg : process(i_clk)
begin
  if rising_edge(i_clk) then
    if i_rst = '1' then
      r_data    <= (others => '0');
      r_valid   <= '0';
      r_counter <= (others => '0');
    else
      r_data    <= i_data;
      r_valid   <= i_valid;
      r_counter <= r_counter + 1;
    end if;
  end if;
end process p_reg;

Instructions séquentielles dans un process

if / elsif / else

process(i_clk)
begin
  if rising_edge(i_clk) then
    if i_rst = '1' then
      r_state <= IDLE;
    elsif i_enable = '1' then
      r_state <= ACTIVE;
    else
      r_state <= r_state;  -- inutile mais explicite
    end if;
  end if;
end process;

case

process(i_clk)
begin
  if rising_edge(i_clk) then
    case r_state is
      when IDLE =>
        if i_start = '1' then
          r_state <= RUNNING;
        end if;
      when RUNNING =>
        if r_done = '1' then
          r_state <= IDLE;
        end if;
      when others =>
        r_state <= IDLE;
    end case;
  end if;
end process;

when others est obligatoire dans un case sur des types non énumérés. C'est une bonne pratique même pour les types énumérés (couvre les cas imprévus).

for / loop

process(i_clk)
  variable v_sum : unsigned(15 downto 0);
begin
  if rising_edge(i_clk) then
    v_sum := (others => '0');
    for i in 0 to 7 loop
      if w_data(i) = '1' then
        v_sum := v_sum + 1;
      end if;
    end loop;
    r_popcount <= v_sum(3 downto 0);
  end if;
end process;

Erreurs courantes

Latch inféré (erreur de logique combinatoire)

-- MAUVAIS : toutes les branches ne couvrent pas toutes les sorties
process(i_sel, i_a, i_b)
begin
  if i_sel = '0' then
    w_out <= i_a;
  end if;
  -- i_sel = '1' → w_out non assigné → latch inféré !
end process;
 
-- BON : valeur par défaut + couverture complète
process(i_sel, i_a, i_b)
begin
  w_out <= i_a;  -- valeur par défaut
  if i_sel = '1' then
    w_out <= i_b;
  end if;
end process;

Les latches sont à éviter sur FPGA (mauvais timing, ressources inefficaces). Toujours couvrir tous les cas dans un process combinatoire.