Distinguer élaboration, simulation et synthèse, puis aborder CDC, latence et généricité avancée.
Une construction VHDL peut agir à l'élaboration, en simulation ou dans le matériel décrit. Distinguer ces moments aide à comprendre les génériques, les structures répétées et la latence.
Phase
Rôle
Exemple
Élaboration
Construire la hiérarchie avant simulation/synthèse
,
generic
generate
Simulation
Exécuter le modèle dans le simulateur
wait for, assert, fichiers
Synthèse
Transformer le RTL en registres, LUT, DSP, BRAM
process, signaux, opérateurs
Créer une structure à l'élaboration
for / generate crée des instances avant l'exécution du modèle :
g_regs : for i in 0 to g_WIDTH - 1 generate U_FF : entity work.dff port map ( i_clk => i_clk, i_d => i_d(i), o_q => o_q(i) );end generate g_regs;
Avec g_WIDTH = 8, cet extrait contient huit instances. Le FPGA ne parcourt pas une boucle logicielle pour les exécuter.
Les génériques fixent une largeur, une profondeur ou une option. VHDL-2008 permet aussi un type générique :
entity delay_line is generic ( type t_DATA; g_DEPTH : positive := 4 ); port ( i_clk : in std_logic; i_d : in t_DATA; o_q : out t_DATA );end entity delay_line;
Le bloc peut alors recevoir plusieurs types de données. Vérifie la prise en charge de cette construction ; des paramètres de taille ou une option booléenne suffisent souvent au besoin.
Séparer RTL et scénario de test
Un code accepté par le simulateur n'est pas nécessairement synthétisable :
Construct
Usage conseillé
wait for 10 ns
Testbench
file, textio, hread
Testbench
real comme signal
Simulation, pas RTL
assert simple
RTL possible, surtout vérification/simulation
rising_edge(i_clk)
RTL synchrone
process(i_clk)
RTL synchrone
Une durée absolue, un fichier ou une suite de stimuli signale souvent du code de testbench. Les fonctions IEEE, fixed_pkg et les packages demandent eux aussi un usage adapté à la simulation ou au calcul matériel.
Traverser les domaines et tenir la latence
Un signal asynchrone peut rendre une bascule métastable. Pour un signal d'un bit suffisamment lent, deux bascules dans le domaine de destination forment un synchroniseur courant :
process(i_clk_dst)begin if rising_edge(i_clk_dst) then r_meta <= i_async; r_sync <= r_meta; end if;end process;
Ce montage réduit le risque sans garantir la capture d'une impulsion trop courte. Pour un bus, synchroniser chaque bit séparément peut donner un mot incohérent. Utilise un handshake, une FIFO asynchrone ou un mécanisme adapté au transfert.
Un pipeline, une FIFO, un filtre ou un calcul itératif ajoute un délai qui doit figurer dans le contrat d'interface :
-- Exemple : i_valid entre au cycle N.-- o_valid doit sortir au cycle N+3 avec la donnée correspondante.
Le testbench vérifie la valeur, son cycle de validité, le reset et les cycles où i_valid = '0'. Donnée et validité doivent rester alignées.
Choisis les constructions pour un besoin précis : generate pour répéter une structure, package pour partager des types, attributs pour déduire les tailles, pipeline pour raccourcir un chemin critique. Garde une logique simple facile à voir.