Aller au contenu

Hiérarchie, génériques et paquetages

La hiérarchie rend les grandes conceptions compréhensibles. Chaque entité doit posséder une responsabilité claire, un contrat temporel explicite et une stratégie de test.

Instanciation directe

u_counter : entity work.counter(rtl)
  generic map (
    G_WIDTH => 24
  )
  port map (
    clk_i    => clk_i,
    reset_i  => reset_i,
    enable_i => tick_s,
    count_o  => count_s
  );

Préférez l'association par nom, plus sûre lorsque les ports sont réordonnés ou complétés. work représente la bibliothèque de compilation courante, pas un dossier.

Génériques

Les génériques configurent le matériel pendant l'élaboration :

entity counter is
  generic (
    G_WIDTH : positive := 8
  );
  port (
    clk_i    : in  std_logic;
    reset_i  : in  std_logic;
    enable_i : in  std_logic;
    count_o  : out unsigned(G_WIDTH - 1 downto 0)
  );
end entity;

Une fonction de paquetage peut calculer une largeur dérivée :

function clog2(value : positive) return natural is
  variable result : natural := 0;
  variable v      : natural := value - 1;
begin
  while v > 0 loop
    result := result + 1;
    v := v / 2;
  end loop;
  return result;
end function;

Traitez explicitement les cas limites afin de ne jamais créer un vecteur de largeur nulle.

Paquetages

Déclaration :

library ieee;
use ieee.std_logic_1164.all;

package display_pkg is
  subtype digit_t is std_logic_vector(3 downto 0);
  type digit_array_t is array (natural range <>) of digit_t;

  function hex_to_segments(digit : digit_t)
    return std_logic_vector;
end package;

Corps :

package body display_pkg is
  function hex_to_segments(digit : digit_t)
    return std_logic_vector is
  begin
    case digit is
      when x"0"   => return "1000000";
      when x"1"   => return "1111001";
      when others => return "1111111";
    end case;
  end function;
end package body;

Utilisation :

use work.display_pkg.all;

Les paquetages conviennent aux types partagés, constantes physiques, fonctions pures, procédures de test et scoreboards. Évitez un paquetage global qui importerait tout partout.

Fonctions et procédures

Une fonction pure ne dépend que de ses arguments et renvoie un résultat. Elle décrit naturellement une logique combinatoire et constitue un excellent modèle de référence.

function parity(data : std_logic_vector) return std_logic is
  variable result : std_logic := '0';
begin
  for index in data'range loop
    result := result xor data(index);
  end loop;
  return result;
end function;

Une procédure peut posséder plusieurs paramètres in, out et inout.

procedure pulse(
  signal target  : out std_logic;
  constant width : time
) is
begin
  target <= '1';
  wait for width;
  target <= '0';
end procedure;

Cette procédure avec attente est réservée au banc de test.

Sommet structurel

Conservez l'entité au sommet du FPGA principalement structurelle :

  1. Nommer les broches avec des noms logiques lisibles.
  2. Synchroniser et filtrer les entrées physiques.
  3. Instancier les blocs fonctionnels.
  4. Relier les sorties.
  5. Laisser les algorithmes dans des sous-entités faciles à tester.

Le cœur réutilisable reste ainsi indépendant de la polarité des broches et de la carte.

Vérifier les génériques

Testez :

  • la plus petite valeur légale ;
  • une valeur typique ;
  • une valeur non puissance de deux lorsque c'est pertinent ;
  • une valeur assez grande pour révéler une erreur de largeur.

Le seul test de la valeur par défaut ne prouve pas la paramétrisation.

Ordre de compilation

  1. Déclarations de paquetages.
  2. Corps de paquetages.
  3. Entités feuilles.
  4. Entités qui les instancient.
  5. Paquetages de banc de test.
  6. Sommets de banc de test.

Vivado gère souvent cet ordre dans un projet. En ligne de commande, énumérez volontairement les dépendances.

Liste de contrôle

  • Chaque entité possède-t-elle une responsabilité exprimable en une phrase ?
  • Horloges, resets, validations et handshakes sont-ils visibles à l'interface ?
  • Les génériques sont-ils typés et contraints ?
  • Les constantes dérivées sont-elles centralisées ?
  • Les paquetages restent-ils cohérents et ciblés ?
  • Le cœur fonctionnel peut-il être simulé sans les broches FPGA ?