Organiser le VHDL avec des packages, fonctions et procédures réutilisables.
Un package donne une définition commune aux fichiers qui en ont besoin. Il peut partager types, sous-types, constantes, déclarations de composants et interfaces de fonctions ou de procédures.
Exposer et utiliser les définitions
La déclaration du package expose les éléments accessibles aux autres unités :
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
package video_pkg is
subtype t_color is unsigned(7 downto 0);
type t_rgb is record
red : t_color;
green : t_color;
blue : t_color;
valid : std_logic;
end record t_rgb;
constant c_RGB_BLACK : t_rgb := (
red => (others => '0'),
green => (others => '0'),
blue => (others => '0'),
valid => '0'
);
function is_valid_pixel(i_pixel : t_rgb) return boolean;
end package video_pkg;
Le package body fournit le corps des sous-programmes déclarés :
package body video_pkg is function is_valid_pixel(i_pixel : t_rgb) return boolean is begin return i_pixel.valid = '1'; end function is_valid_pixel;end package body video_pkg;
Types et constantes peuvent être entièrement définis dans la déclaration. Le package fournit des définitions réutilisables ; son import ne crée pas à lui seul un bloc matériel.
Importe-le avant l'unité qui utilise ses éléments :
library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.NUMERIC_STD.ALL;library work;use work.video_pkg.ALL;entity pixel_gate is port ( i_pixel : in t_rgb; o_red : out std_logic_vector(7 downto 0) );end entity pixel_gate;architecture rtl of pixel_gate isbegin o_red <= std_logic_vector(i_pixel.red) when is_valid_pixel(i_pixel) else x"00";end architecture rtl;
Un type présent dans les ports doit être visible avant la déclaration de l'entité. Ce partage évite de maintenir plusieurs définitions divergentes de la même interface.
Retourner une valeur avec une fonction
Une fonction retourne un résultat. Celle-ci calcule une parité paire :
function parity_even(i_data : std_logic_vector) return std_logic is variable v_parity : std_logic := '0';begin for i in i_data'range loop v_parity := v_parity xor i_data(i); end loop; return v_parity;end function parity_even;
w_parity <= parity_even(i_data);
Pour le RTL, garde les fonctions simples, déterministes et sans effets de bord. Elles expriment un calcul, sans créer de délai de simulation ni de cycle d'horloge supplémentaire. Une fonction ne peut pas contenir de wait.
Factoriser des actions avec une procédure
Une procédure peut modifier des paramètres out ou inout plutôt que retourner une valeur unique :
procedure drive_byte( signal o_bus : out std_logic_vector(7 downto 0); constant i_value : in natural) isbegin o_bus <= std_logic_vector(to_unsigned(i_value, o_bus'length));end procedure drive_byte;
Dans un testbench, l'appel suivant applique un octet puis attend le front :
drive_byte(w_data, 16#A5#);wait until rising_edge(i_clk);
En RTL, les instructions factorisées prennent le contexte de leur appel, combinatoire ou séquentiel. Le code synthétisable doit rester compatible avec le matériel visé ; les attentes temporelles servent au testbench.
Besoin
Choix
Calculer une valeur
Fonction
Factoriser une vérification de testbench
Procédure
Modifier plusieurs sorties
Procédure
Partager des types et constantes
Package
Organise les packages autour d'un rôle clair, par exemple video_pkg, spi_pkg ou test_utils_pkg. Sépare les aides de test des interfaces matérielles lorsque cela facilite leur usage et importe seulement les dépendances nécessaires.