Aller au contenu

Recettes RTL réutilisables

Ce sont des points de départ. Adaptez polarité, largeur, latence et interface.

Registre avec validation

process(clk_i)
begin
  if rising_edge(clk_i) then
    if reset_i = '1' then
      data_q <= (others => '0');
    elsif enable_i = '1' then
      data_q <= data_i;
    end if;
  end if;
end process;

Compteur montant

process(clk_i)
begin
  if rising_edge(clk_i) then
    if reset_i = '1' then
      count_q <= (others => '0');
    elsif enable_i = '1' then
      count_q <= count_q + 1;
    end if;
  end if;
end process;

Un unsigned revient naturellement à zéro après son maximum. Pour saturer, comparez avant l'incrément.

Compteur modulo-N avec tick

process(clk_i)
begin
  if rising_edge(clk_i) then
    tick_o <= '0';
    if reset_i = '1' then
      count_q <= 0;
    elsif count_q = G_MODULUS - 1 then
      count_q <= 0;
      tick_o  <= '1';
    else
      count_q <= count_q + 1;
    end if;
  end if;
end process;

Imposez G_MODULUS > 0 par assertion.

Synchroniseur deux bascules

signal sync_q : std_logic_vector(1 downto 0) := (others => '0');
attribute ASYNC_REG : string;
attribute ASYNC_REG of sync_q : signal is "TRUE";

process(clk_i)
begin
  if rising_edge(clk_i) then
    sync_q <= sync_q(0) & async_i;
  end if;
end process;

sync_o <= sync_q(1);

Vérifiez le sens de concaténation : le bit 0 reçoit l'entrée puis le bit 1 reçoit l'ancien bit 0.

Détecteur de front montant

process(clk_i)
begin
  if rising_edge(clk_i) then
    if reset_i = '1' then
      previous_q <= '0';
      pulse_o    <= '0';
    else
      pulse_o    <= level_i and not previous_q;
      previous_q <= level_i;
    end if;
  end if;
end process;

Le signal d'entrée doit déjà être synchrone.

Anti-rebond

Algorithme :

  1. Synchroniser l'entrée.
  2. Si l'échantillon égale la sortie acceptée, remettre le compteur à zéro.
  3. Sinon incrémenter.
  4. Au seuil, accepter le niveau et remettre le compteur à zéro.

À 100 MHz, 10 ms représentent 1 000 000 cycles. Exprimez la durée en cycles ou dérivez-la de G_CLOCK_HZ.

Registre à décalage

process(clk_i)
begin
  if rising_edge(clk_i) then
    if enable_i = '1' then
      shift_q <= shift_q(shift_q'high - 1 downto 0) & serial_i;
    end if;
  end if;
end process;

Documentez le sens et l'extrémité contenant le bit le plus récent.

Encodeur de priorité

process(all)
begin
  valid_o <= '0';
  index_o <= (others => '0');
  for index in request_i'reverse_range loop
    if request_i(index) = '1' then
      valid_o <= '1';
      index_o <= to_unsigned(index, index_o'length);
      exit;
    end if;
  end loop;
end process;

Le sens de boucle définit la priorité. Testez plusieurs requêtes simultanées.

Calcul d'une validation

Pour F_CLK et F_TICK :

DIVISOR = F_CLK / F_TICK

Le résultat n'est exact que si la division tombe juste. Sinon, un accumulateur de phase fournit un rapport fractionnaire plus précis.

Handshake valid/ready

transfer_s <= valid_i and ready_o;
  • Le producteur maintient valid et les données jusqu'au transfert.
  • Le consommateur lève ready lorsqu'il peut accepter.
  • Éviter toute boucle combinatoire via valid/ready.

Balayage sept segments

Associez un générateur de tick, un index de deux bits, un mux de chiffre, un décodeur hexadécimal et des activations one-hot actives à zéro. Un bref blanc entre changements peut supprimer le ghosting.

Tick UART

À 115 200 bauds et 100 MHz, le diviseur entier vaut environ 868. Calculez et documentez le débit réel. Pour la réception, créez souvent une validation 8× ou 16× et échantillonnez au centre du bit.

Règle de vérification

Chaque recette réutilisable doit tester reset, validation/maintien, minima, maxima, transition limite, génériques extrêmes et contrat de latence.