Le langage Verilog, bien que très différent du point de vue syntaxique, répondait à des besoins similaires. Il existe de fait une quasi équivalence entre les deux langages, d'où l'existence de nombreux scripts de traduction de l'un vers l'autre. Le langage VHDL est maintenant le langage de description matérielle majoritairement utilisé par les entreprises européennes alors que Verilog est souvent préféré de l'autre côté de l'Atlantique.
Certains concepts, comme les fichiers ou l'échelle de temps, n'ont de sens que pour la modélisation d'un composant électronique et ne sont pas accessibles au composant lui-même. L'affichage d'une chaîne de caractères sur la sortie standard étant également un concept abstrait, elle n'est possible qu'en simulation.
-- Déclaration de l'entité entity hello_world is end entity hello_world; -- Déclaration de l'architecture architecture wiki of hello_world is begin -- Process affiche_texte affiche_texte: process is begin -- Afficher la chaine de caractère "Hello world !" sur la sortie standard du simulateur report "Hello world !"; -- Suspendre l'exécution du process wait; end process affiche_texte; end architecture wiki;
Il existe plusieurs descriptions possibles d'un composant dont l'une de ses sorties change d'état après un temps déterminé.
-------------------------------------------------------------------------------- -- Liste des librairies et objets importés library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; -------------------------------------------------------------------------------- -- Déclaration de l'entité entity Clignotant is -- Paramètres passés lors de la génération (compilation ou synthèse) generic ( PERIODE : integer := 100000000; DUREE_ETAT_BAS : integer := 75000000 ); -- Entrées / sorties port ( CLK : in std_logic; RESET : in std_logic; LED : out std_logic ); end entity Clignotant; -------------------------------------------------------------------------------- architecture RTL of Clignotant is -- Déclaration des signaux utilisés dans l'implémentation signal Compteur_s : std_logic_vector(31 downto 0); begin -- Process synchrone "Compteur" Compteur: process(CLK) begin if rising_edge(CLK) then -- La suite est exécutée après chaque front montant de l'entrée CLK if (RESET = '1') then -- Reset actif à l'état haut Compteur_s <= (others => '0'); LED <= '0'; else if (Compteur_s < DUREE_ETAT_BAS) then -- Maintenir la LED éteinte LED <= '0'; else -- Allumer la LED LED <= '1'; end if; if (Compteur_s >= PERIODE) then -- Recommencer un cycle Compteur_s <= (others => '0'); else -- Continuer le cycle Compteur_s <= Compteur_s + 1; end if; end if; end if; end process Compteur; -- Fin du process "Compteur" end architecture RTL; -- Fin du fichier
En VHDL, il faut distinguer le contenant du contenu, nommés respectivement entité et architecture.
Un fichier VHDL doit toujours porter le nom de l'entité qu'il contient (ceci est une règle d'utilisation qui aide à la clarté, elle est même obligatoire avec certains logiciels). Son extension standard est « .vhd », bien que l'on écrive parfois « .vhdl ». Avant toute chose, il faut commencer par déclarer l'utilisation des bibliothèques nécessaires au projet :
-- En VHDL: une ligne de commentaires commence avec deux "-" -- Il préférable de commencer par importer les bibliothèques VHDL standards normalisées par l'IEEE, -- car elles sont nécessaires dans une grande partie des cas. library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all;
Les bibliothèques std_logic_arith, std_logic_signed et std_logic_unsigned, malgré leur nom, ne sont pas normalisées par l'IEEE et leur utilisation est fortement déconseillée. En effet, il est préférable de préciser explicitement le type de chaque vecteur sur lequel on fait une opération (SIGNED ou UNSIGNED) de manière à spécifier son traitement arithmétique. Le comportement des opérations sur les types STD_LOGIC_VECTOR sera différent selon la bibliothèque appelée, ce qui rend leur utilisation hasardeuse.
Nous décrivons en premier lieu l'interface (l'entité) d'un composant multiplexeur, entité qui nous servira pour les trois exemples d'architectures concurrentes permettant de réaliser un multiplexeur.
-- Voici un exemple d’entité, décrivant les E/S utilisées -- par les trois exemples d’architectures purement concurrentes: -- -- ATTENTION, avec certains outils de CAO, l'entité doit avoir le même nom que le fichier (logique_3_vers_1.vhd) ENTITY logique_3_vers_1 IS PORT ( a : IN STD_LOGIC; b : IN STD_LOGIC; c : IN STD_LOGIC; adr : IN STD_LOGIC_VECTOR (1 downto 0); s : OUT STD_LOGIC ); END logique_3_vers_1;
La première architecture permettant de décrire ce multiplexeur utilise directement une formulation booléenne, particulièrement adaptée aux équations simples. Cette méthode est très souple et permet d'écrire toute fonction combinatoire. En contrepartie, elle est peu lisible pour les équations complexes.
-- Première architecture concurrente décrivant un mux: ARCHITECTURE mux_3_vers_1 OF logique_3_vers_1 IS BEGIN s <= ( a AND NOT adr(1) AND NOT adr(0) ) OR ( b AND NOT adr(1) AND adr(0) ) OR ( c AND adr(1) AND NOT adr(0) ); -- OR ('0'AND adr(1) AND adr(0) ); -- Cette dernière ligne est implicite dans l'équation du dessus END mux_3_vers_1;
La deuxième architecture permettant de décrire ce multiplexeur est limitée aux fonctions dont le nombre d'entrées est fixée (n). Elle offre une grande clarté de lecture. Cependant, si on veut que le signal s soit piloté correctement, il est nécessaire de prévoir l'ensemble des états possibles (9^n, car le type std_logic peut prendre 9 valeurs). Cela est fait grâce au cas others. Le comportement en simulation d'un tel multiplexeur sera subtilement différent du premier car les nuances des différentes valeurs de STD_LOGIC ne sont pas traitées. Toute valeur autre que 1 ou 0 mène à un X (conflit).
-- Deuxième architecture concurrente décrivant un mux: ARCHITECTURE mux_3_vers_1 OF porte_3_vers_1 IS BEGIN WITH adr SELECT s <= a WHEN "00", b WHEN "01", c WHEN "10", '0' WHEN "11", 'X' WHEN others; END mux_3_vers_1;
La dernière ligne permet de regrouper tous les cas non explicitement traités en une seule ligne.
La troisième architecture permettant de décrire ce multiplexeur est elle aussi limitée aux fonctions dont le nombre d'entrées est fixée (n) pour lesquelles elle est tout particulièrement adaptée. Cependant, avec cette méthode il n'est pas obligatoire de lister l'ensemble des états possible, puisque la dernière ligne permet d'appliquer un traitement par défaut. Là encore, le comportement sera légérement différent puisqu'on ne crée plus d'état 'X' mais qu'on ne gère pas non plus les nuances d'états comme le font les opérateurs booléens.
-- Troisième architecture concurrente décrivant un mux: ARCHITECTURE mux_3_vers_1 OF porte_3_vers_1 IS BEGIN s <= a WHEN adr = "00" ELSE b WHEN adr = "01" ELSE c WHEN adr = "10" ELSE '0'; END mux_3_vers_1;
La description d'une architecture séquentielle, c’est-à-dire avec l'aide d'une fonction dépendante du temps (ie. de l'horloge) passe par l'utilisation de process.
-- Architecture séquentielle pour une bascule D: ARCHITECTURE comport OF bascule_d IS BEGIN bascule : PROCESS (clk, reset) BEGIN IF reset = '1' THEN q <= '0'; ELSE IF clk'event AND clk = '1' THEN -- équivalent à: IF rising_edge(clk) THEN q <= d; END IF; END IF; END bascule; END comport;