CHAPITRE 3 : LE LANGAGE VHDL ET LA CONCEPTION DE
CIRCUITS
3.1 UIntroductionU
En analysant l'évolution de la production industrielle
d'ASICS (Application Specific Integrated Circuit) ou de FPGA (Field
Programmable Gate Array), on constate que ceux-ci, bénéficiant
des progrès technologiques, sont de plus en plus complexes. On sait
intégrer à l'heure actuelle sur silicium des millions de portes
pouvant fonctionner à des fréquences supérieures à
600 MHz. On parle beaucoup de SOC (System On a Chip). En effet, plus de 80% des
ASICS futurs comporteront un ou plusieurs microprocesseurs. Par ailleurs, si on
considère qu'un ingénieur confirmé valide 100 portes par
jour, il lui faudrait 500 ans pour un projet de 12 millions de portes et ceci
pour un coût de 75 millions de dollars. Ceci parait totalement absurde et
si c'est pourtant réalisable cela est uniquement dû à
l'évolution des méthodes de CAO (flot de conception en spirale,
équipes travaillent en parallèle) intégrant en particulier
la réutilisation efficace d'un savoir antérieur. Le concepteur va
travailler avec des IP (Intellectual Property) s'il est intégrateur de
système, mais il peut être lui-même développeur d'IP
et la méthode qui devra le guider est appelée Design Reuse. Ces
expressions désignent des composants génériques incluant
des méthodes d'interfaçages rigoureuses et suffisamment
normalisées pour pouvoir être rapidement inclus dans un design
quelconque.
Dans ce chapitre, nous ferons comme nous l'avons
précisé en introduction, une brève présentation du
langage VHDL en présentant ici dans un premier temps son historique et
ensuite sa syntaxe. Nous terminerons ce chapitre par des exemples de
programmes.
3.2 UHistorique du VHDL (Very
High Speed Integrated Circuit, Hardware
Description Language) [11]
1980 Début du projet VHDL
financé par le US DoD
1985 Première version 7.2
publique
1987 Première version du standard IEEE Std
1076-1987
1993 Mise à jour du standard (IEEE Std
1076-1993)
2002 Mise à jour du standard (IEEE Std
1076-2002)
UTableau3.2aU :
UHistorique du VHDLU
Le langage VHDL est un standard IEEE depuis 1987 sous la
dénomination IEEE Std. 1076-1987 (VHDL-87). Il est sujet à
révision tous les cinq ans. Une première révision, qui
corrige certaines incohérences de la version initiale et qui ajoute de
nouvelles fonctionnalités, a eu lieu en 1994 (IEEE Std. 1076-1993 ou
VHDL-93). La dernière révision est celle de 2002 (IEEE Std.
1076-2002 ou VHDL-2002).
L'IEEE (Institute of Electrical and Electronics Engineers) est
un organisme international qui définit entre autres des normes pour la
conception et l'usage de systèmes électriques et
électroniques.
3.3 USYNTAXEU [15]
Nous présentons d'abord la structure d'un module en
VHDL.
3.3.1 U Les librairies
U
Les librairies contiennent les fonctions et les types dont
nous avons besoin pour compléter le module défini ci-dessous.
Ces outils sont constitués en paquets (packages) et on
y accède par le mot clé use.
Voici la syntaxe de la déclaration d'une
bibliothèque :
library
<nom_librairie> ;
use
<nom_librairie>.<nom_package>.[all
| <part>] ;
U
ExempleU :
library IEEE ;
use
IEEE.std_logic_1164.all ;
use
IEEE.std_logic_arith.all;
use
IEEE.std_logic_unsigned.all;
3.3.2 ULa déclaration
d'entité
Une entité doit définir l'interface pour un
module. La déclaration d'une entité commence par le nom de
l'entité <nom_entité> et se termine bien sûr par le
end de la déclaration. Ensuite c'est la déclaration des ports
en précisant au cas échéant les ports d'entrées et
de sorties de notre module. Voici donc présenté ci-dessous
l'interface de notre conception, et précisons ici que les
déclarations sont lues ou établie non sans l'accompagnement
d'une architecture.
entity <nom_entite> is
port ( <nom_port> :
<mode> <type> ;
<autre_ ports>...
) ;
end <nom_entite> ;
U
ExempleU :
entity entite_or is
port (
input_1 : in std_logic;
Input_2: in std_logic;
Output: out std_logic);
end entité_or;
3.3.3 UArchitectureU
Une architecture présente plusieurs autres styles de
syntaxe VHDL, mais en ce qui nous concerne dans ce document nous n'allons pas
parler d'eux toutes mais nous présenterons ici celles qui sont les plus
utilisées dans ce chapitre. Pour maintenant donc, nous en
présentons juste une simple liste.
Voici donc la syntaxe d'une architecture :
architecture <nom_arc> of
<nom_entite> is
--liste de déclaration (déclarations des signaux,
déclaration des composants, etc.)
begin
-- corps de l'architecture
end <nom_arc>
UExempleU :
architecture arc_entite_or of
entite_or is
output: out std_logic;
Input_1, input_2: in std_logic;
begin
output <= input or input_2;
end arc_entité_or;
Maintenant nous allons présenter la syntaxe des
déclarations ne faisant obligatoirement partie de notre module.
3.3.4 UDéclarations des
signauxU
Très souvent, nous aurons besoin de signaux internes
dans le comportement de notre architecture. Ceci pourrait être une valeur
interne à stocker ou plutôt des composants à connecter,
toutefois les déclarations restent inchangées et sont toutes
faites entre les mots clés is et begin
de l'architecture.
En voici donc la syntaxe :
signal <nom_signal> :
type ;
UExemplesU :
signal port_i :
std_logic ;
signal bus_signal :
std_logic_vector(15 downto 0) ;
signal count : integer range 0 to
31;
3.3.5 UDéclaration des constantsU
Occasionnellement, nous aurons besoin de déclarer des
constants. Leur syntaxe est la suivante :
constant <nom_constant > :
type := < valeur_initiale> ;
UExemplesU :
constant etat_1 :
std_logic_vector := `'01'' ;
constant etat_2 :
std_logic_vector := `'10'' ;
constant addr_max :
integer :=1024 ;
3.3.6 UDéclaration de composantsU
Nous aurons à les utiliser assez fréquemment
puisqu'ils sont une clé pour la description structurale de nos modules.
Essentiellement, ceux-ci sont une déclaration d'interface, ainsi
l'architecture dont l'architecture devra en tenir compte. Les gammes de
syntaxe marcherons si cette déclaration correspond à son usage,
mais cela synthétisera uniquement si la déclaration correspond
à un composant existant. Très souvent, il est possible de
simplement recopier la déclaration de l'entité du composant et de
changer le mot clé `entity' par `component `.
En voici donc la syntaxe de la déclaration :
component <nom_component> is
port (
les déclarations de ports ayant aussi été
faite dans la déclaration « entity » ;
end component;
UExempleU :
component or_entit
is
port ( input_1 : in std_logic ;
input_2: in std_logic;
output : out std_logic);
end component;
3.3.7 UDeclarations de variableU
Les variables sont beaucoup utilisées pour garder la
trace de certaines valeurs dans le contexte d'un processus ou d'une fonction,
mais ne peuvent être utilisées en dehors des processus or
fonctions. Par ailleurs, elles ne représentent pas
nécessairement un fils dans l'appareil et sont traitées par
l'outil de synthétisation séquentielle. Ceci signifie qu'elles ne
se comportent pas nécessairement comme le font les signaux.
Leur syntaxe est la suivante :
variable <nom_variable> is :
type;
UExemplesU :
variable count_v : integer range 0
to 15;
variable data_v : std_logic_vector (7
downto 0);
variable condition_v: Boolean;
3.3.8 UDéclarations de typeU
Le mot clé type nous permet de
définir notre propre type de données en VHDL. Ceux-ci sont
interprétés et subséquentiellement
synthétisés par les outils de synthétisation. Nous pouvons
utiliser les types pour créer nos propres types de données ou des
tableaux de types de données existant.
Leur syntaxe est la suivante :
type <nom_type>
is (<value>);
UExemplesU :
type enum_type
is (a,b,c, ...,z);
type int_array is array
integer range 0 to 3;
3.3.9 UExpressions logiquesU
Le fondement de la plus part du VHDL que nous écrirons
est l'interaction logique entre les signaux dans notre module.
En voici la syntaxe :
[not] <identificateur>
[and | or |
nor | nand |
xor | xnor | ...]
[<identificateur>]
];
UExemple U:
not signal_1;
signal_1 and signal_2;
(not signal_1)
and (signal_2 xor (signal_3
or not signal_4))
3.3.10 UDéclarations
If-Then-elseU
En voici la syntaxe :
if <condition>
then instructions
[elseif <condition>
then instructions
else instructions]
end if.
UExempleU :
if condition_v_1='1'
then
out_vector <='001'
elseif condition_v_2='1'
then
out_vector <=»110»
else
out_vector <= «000»
end if ;
3.3.11 UDéclaration CaseU
Voici sa syntaxe :
case <expression>
is
when <choice(s)> =>
<assignments>;
when ...
[when others => ... ]
end case;
UExempleU :
case scancode
is
when x»14» =>
integer_signal<= 1;
when x»18» =>
integer_signal<= 2;
when x»19» |
x»20» | x»21» | => integer_signal<= 3;
when others
=> integer_signal <= 0;
end case ;
Maintenant dans ce qui suit nous présentons la syntaxe
structurale.
3.3.12 USignaux assignésU
Voici la syntaxe :
<signal_name> <= <expression> ;
UExempleU :
std_logic_signal_1 <= not
std_logic_signal_2;
std_logic_signal <= signal_a and
signal_b;
large_vector (15 downto 6) <= small_vector (10 downto 0);
3.3.13 UVariable assignéeU
Les variables assignées ne sont pas si
différentes des signaux assignés. La différence clé
se trouve dans l'opérateur d'assignation qui est différent. Nous
pouvons cependant assigner à partir des variables pour les signaux et
vice versa.
En voici la syntaxe :
<nom_variable> := <expression>
UExempleU :
boolean_v:= true;
temp_v (3 downto 0):= s1_vector_signal
(7 downto 4);
3.3.14 ULes processusU
Les processus sont généralement les piliers du
comportement de notre code. Ils facilitent la spécification des
horloges aussi bien que leur synchronisation parmi les signaux assignés.
En général, nous utiliserons les processus lorsque un signal
assigné est dépendant du changement d'un autre.
Syntaxe :
[<nom_processus> :] process
(<signaux sensibles>)
déclarations de variable
déclarations de constantes
begin
instructions
end process;
UExempleU :
output_process: process
(flag_signal)
begin
if flag_signal = `1'
then
output_vector <= «010»;
else
output_vector <= «101»;
end if;
end process;
3.3.15 UInstantiation de composantU
Juste au tant que les processus sont les pilliers du
comportement de notre code, l'instantiation de composant est la clé des
caractéristiques de notre code structural.
Voici sa syntaxe :
<identificateur_composant> : <nom_composant>
port map(
<nom_port> => <signal_assigne>,...
) ;
UExempleU :
or_ent_1 : or_entity
port map(
input_1 => input_1_sig,
input_2 =>input_2_sig,
output=> output_sig);
Dans cette partie nous présentons les différents
types de données que l'on rencontre dans le VHDL.
3.3.16 Ustd_logicU
Le type de données std_logic est le plus couramment
utilisé en VHDL. Il est une partie du package std_logic_1164 dans la
librairie IEEE et est utilisé pour représenter des valeurs
logiques à deux états réguliers (tels que `0' et `1')
aussi bien que d'autres valeurs logiques communes tel que la haute
impédance (`Z').
Par ailleurs pour ce type de données c'est le
std_logic_vector, qui représente des bus en VHDL. Ce type de
données agit comme un tableau de std_logic `bits' et en outre
représente une collection telle que
STD_LOGIC --
`U' ,'X','0','1','Z','W','L','H','-`
STD_LOGIC_VECTOR -- rangé naturelle de
STD_LOGIC
3.3.17 UbooleanU
Un autre type logique est le type booléen. C'est un
type standard de VHDL qui est typiquement utilisé comme une variable ou
comme une constante pour signifier le sort d'une condition.
BOOLEAN
-- vrai ou faux
3.3.18 UbitsU
BIT
-- `0','1'
BIT_VECTOR (Natural) --
Tableau de bits
3.3.19 Utypes rangésU
Il y a un couple de moyens permettant la représentation
des nombres en VHDL. L'un d'entre eux est utilisé pour la
représentation en binaire/hexadécimal qui n'est pas possible par
le std_logic_vector. Alors que ceci est pleinement possible pour
représenter des signaux physiques, les entiers quand à eux sont
plus faciles à utiliser. En tant que tel, un type entier et deux sous
types ont été définis en VHDL. Il y a cependant, un petit
problème. Les entiers ne sont pas implémentés en fils. Ils
sont translatés par bus. par conséquent, pour limiter les fils
physiques qui sont implémentés par la conception, et par la
suite rendre l'implémentation de la conception plus efficace, nous
préférons limiter les entiers à des rangées bien
spécifiées.
INTEGER
-- 32 or 64 bits
NATURAL
-- entiers >= 0
POSITIVE
-- entiers > 0
3.3.20 UOpérateurs logiques
et arithmétique définis dans le langage VHDLU [12]
[15]
Expression = formule pour calculer une valeur
Priorité des opérateurs (de la plus basse
à la plus haute)
· Logiques: and or nand nor xor xnor
· Relationnels: = /= < <= >
>=
· Décalage et rotations: sll srl sla
sra rol ror
· Addition: + - &
· Signe (unaires): + -
· Multiplication: * / mod
rem
· Divers: ** abs
not
UExemplesU
-- soient PI et R de type real
PI*(R**2) / 2
2.0*PI*R
-- soient A et B de type integer
B /= 0 and A/B > 1 -- court-circuit
A**2 + B**2
4*(A + B)
(A + 1) mod B
-- soient A, B et C de type boolean
A and B and C --
évaluation de gauche à droite
-- idem pour or, xor and
xnor
A nor (B nor C) --
parenthèses requises, nor pas associatif
-- idem pour nand
Une expression est une formule qui spécifie comment
calculer une valeur. Une expression est constituée d'opérandes
(termes) et d'opérateurs.
Les termes d'une expression sont typiquement des valeurs
littérales (p.ex. B"001101") ou des identificateurs représentant
des objets (constantes, variables, signaux).
Les opérateurs sont associés à des types.
Chaque opérateur appartient à un niveau de
précédance ou de priorité qui définit
l'ordre dans lequel les termes de l'expression doivent être
évalués. L'usage de parenthèse permet de rendre les
niveaux de priorité explicites ou de changer les niveaux par
défaut.
Les opérateurs logiques and,
nand, or et nor utilisent un
mécanisme de court-circuit lors de
l'évaluation.
L'opérateur and/nand
n'évalue pas le terme de droite si le terme de gauche
s'évalue à la valeur '0' ou false.
L'opérateur or/nor
n'évalue pas le terme de droite si le terme de gauche
s'évalue à la valeur '1' ou true.
Les opérateurs relationnels ne peuvent s'appliquer que
sur des opérandes de même type et retournent toujours une valeur
de type boolean. Les opérandes doivent être d'un type scalaire ou
de type tableau mono-dimensionnel avec éléments d'un type discret
(entier ou énuméré). Les opérateurs "=" et "/=" ne
peuvent pas avoir des opérandes de type fichier.
3.4 Ules paquetagesU
[11]
Un paquetage permet de grouper des déclarations et des
sous-programmes et de les stocker dans une bibliothèque.
package nom-paquetage
is
{ déclaration [ | corps-sous-programme ]
}
end [ package ] [
nom-paquetage ] ;
en-tête de paquetage
package body nom-paquetage
is
{ déclaration [ | corps-sous-programme ]
}
end [ package body ]
[nom-paquetage ] ;
corps de paquetage
Exemple: en-tête de paquetage ne contenant
que des déclarations de
constantes et de (sous-)types.
Ci-dessous nous avons donnés quelques paquetages et
leur description.
3.4.1 U Paquetage
STANDARDU
package STANDARD is
type boolean is (false,
true);
type bit is ('0', '1');
type character is ( ... 256
caractères 8 bits... );
type severity_level is (note,
warning, error, failure);
type integer is range
dépend de l'implantation;
subtype natural is integer
range 0 to integer'high;
subtype positive is integer
range 1 to integer'high;
type real is range
dépend de l'implantation;
type time is range
dépend de l'implantation
units
fs; ps = 1000 fs; ...; hr = 60 min;
end units;
subtype delay_length is time
range 0 to time'high;
impure function now return
delay_length;
type string is array (positive
range <>) of character;
type bit_vector is array
(natural range <>) of bit;
type file_open_kind is
(read_mode, write_mode, append_mode);
type file_open_status is
(open_ok, status_error, name_error, mode_error);
attribute foreign: string;
end package
Le paquetage STANDARD déclare les types et sous-types
prédéfinis du langage, la fonction now (qui retourne le temps
simulé courant) et l'attribut foreign.
Les déclarations du paquetage STANDARD sont
automatiquement visibles dans toute unité de conception. Il se trouve
dans bibliothèque STD.
3.4.2 UPaquetage
TEXTIOU
package TEXTIO is
type line is access string;
type text is file of string;
type side is (right, left);
subtype width is natural;
file input: text open read_mode is "std_input";
file output: text open write_mode is "std_output";
procedure readline (file f: text; l: out line);
procedure writeline (file f: text; l: inout line);
-- pour chaque valeur de type prédéfini:
procedure read (l: inout line; value: out bit; good: out
boolean);
procedure read (l: inout line; value: out bit);
...
procedure write (l: inout line; value: in bit; justified: in
side: = right; field: in width := 0);
...
procedure write (l: inout line; value: in real; justified: in
side := right;
field: in width := 0; digits: in natural := 0);
procedure write (l: inout line; value: in time; justified: in
side := right;
field: in width := 0; unit: in time := ns);
end package TEXTIO;
Le paquetage prédéfini TEXTIO déclare des
types et des sous-programmes pour la manipulation de fichiers textes. Il
déclare aussi des procédures pour lire et écrire les
valeurs d'objets de types prédéfinis.
La lecture d'un fichier texte est effectuée en deux
étapes: 1) lire une ligne complète avec la procédure
readline et stocker la ligne dans un tampon de type line, 2) lire chaque
élément de la ligne lue avec l'une des versions de la
procédure read relative au type de valeur à lire. La
procédure read peut retourner l'état de l'opération par le
paramètre good.
L'écriture dans un fichier est aussi effectuée
en deux étapes:
1) une ligne complète est construite dans un tampon de
type line au moyen d'une des versions de la procédure write, en fonction
des types de valeurs à écrire,
2) la ligne est écrite dans le fichier avec la
procédure writeline.
Notes:
· Si L est le tampon stockant une ligne lue dans un
fichier, chaque opération read sur L consomme un élément
et a pour effet que la valeur retournée par L'length
décroît. La fin de la ligne est ainsi atteinte lorsque L'length =
0.
· La fonction endfile qui teste la fin de fichier est
implicitement déclarée lors de la déclaration du type
fichier text.
L'utilisation du paquetage TEXTIO dans une unité de
conception requiert la spécification d'une clause de contexte.
Ce paquetage se trouve dans la bibliothèque STD
Requiert la clause de contexte use
STD.TEXTIO.all;
3.4.3 UPaquetage STD_LOGIC_1164
(déclaration)
package STD_LOGIC_1164 is
type std_ulogic is ('U', --
un-initialised
'X', -- forcing unknown
'0', -- forcing 0
'1', -- forcing 1
'Z', -- high impedance
'W', -- weak unknown
'L', -- weak 0
'H', -- weak 1
'-' -- don't care);
type std_ulogic_vector is array
(natural range <>) of
std_ulogic;
function resolved (s: std_ulogic_vector)
return std_ulogic;
subtype std_logic is resolved
std_ulogic;
type std_logic_vector is array
(natural range <>) of
std_logic;
-- opérateurs logiques surchargés
and, nand, or,
nor, xor, xnor,
not
-- fonctions de conversion: to_bit, to_bitvector, to_stdulogic,
to_stdlogicvector,
to_stdulogicvector
-- plus autres fonctions...
end package STD_LOGIC_1164;
Le paquetage STD_LOGIC_1164 ne fait pas partie de la
définition du langage VHDL, mais est défini comme un standard
séparé.
Le paquetage déclare deux types logiques à neuf
états std_ulogic (non résolu) et std_logic (résolu):
· Les états '0', '1' et 'X'
représentent respectivement l'état faux, vrai et inconnu (ou
indéterminé).
· Les états 'L', 'H' et 'W'
représentent des états résistifs du type pull-down
ou pull-up.
· L'état 'Z' représentent un
état haute-impédance.
· L'état 'U' est l'état initial par
défaut et identifie les signaux qui n'ont pas été
affectés en simulation.
· L'état '-' est parfois utilisé pour
des vecteurs de test ou en synthèse pour spécifier que certains
bits ne sont pas importants.
Le paquetage déclare des versions des opérateurs
logiques pour ces nouveaux types. Il n'est par contre pas possible d'utiliser
sans autre des opérateurs arithmétiques sur des objets
appartenant à ces types.
L'utilisation du paquetage STD_LOGIC_1164 dans une
unité de conception requiert la spécification d'une clause de
contexte. Il se trouve dans bibliothèque IEEE.
Requiert la clause de contexte
library IEEE;
use IEEE.std_logic_1164.all;
3.4.4 UPaquetage STD_LOGIC_1164 (corps)
Corps du paquetage (extrait)
package body STD_LOGIC_1164 is
...
type stdlogic_table is array (std_ulogic, std_ulogic) of
std_ulogic;
constant resolution_table : stdlogic_table := (
--| U X 0 1 Z W L H - |
('U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U'), -- | U |
('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'), -- | X |
('U', 'X', '0', 'X', '0', '0', '0', '0', 'X'), -- | 0 |
('U', 'X', 'X', '1', '1', '1', '1', '1', 'X'), -- | 1 |
('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', 'X'), -- | Z |
('U', 'X', '0', '1', 'W', 'W', 'W', 'W', 'X'), -- | W |
('U', 'X', '0', '1', 'L', 'W', 'L', 'W', 'X'), -- | L |
('U', 'X', '0', '1', 'H', 'W', 'W', 'H', 'X'), -- | H |
('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X') -- | - |);
...
...
function resolved (s : std_ulogic_vector) return std_ulogic is
variable result : std_ulogic := 'Z'; -- default state
begin
if s'length = 1 then return s(s'low); -- single driver case
else
for i in s'range loop
result := resolution_table(result, s(i));
end loop;
end if;
return result;
end function resolved;
...
end package body STD_LOGIC_1164;
Le corps de paquetage inclut les corps des sous-programmes
déclarés dans la déclaration de paquetage
correspondante.
A titre d'exemple, la fonction de résolution resolve
utilise une table constante resolution_table pour définir les valeurs
résolues de toutes les paires de sources possibles. Le corps de la
fonction traite d'abord le cas pour lequel le signal résolu n'a qu'une
seule source de manière à optimiser le temps de calcul. Dans le
cas contraire, une boucle est utilisée pour appliquer la table de
résolution à chaque source du signal.
3.4.5 UPaquetages
mathématiques U
package MATH_REAL is
-- constantes e, pi et dérivées
-- fonctions sign, ceiling, floor, round, min, max
-- procédure random
-- racine carrée, racine cubique, exponentiation
-- fonction exponentielle et logarithmes
-- fonctions trigonométriques (sin, cos, tan, etc.)
-- fonctions hyperboliques (sinh, cosh, tanh, etc.)
end package MATH_REAL;
package MATH_COMPLEX is
-- type complexe (formes cartésienne et polaire)
-- constantes 0, 1 et j
-- fonctions abs, argument, negation, conjugate
-- racine carrée, exponentiation
-- fonctions arithmétiques avec opérandes
cartésiens et polaires
-- fonctions de conversion
end package MATH_COMPLEX;
Seuls les opérateurs arithmétiques de base sont
a priori disponibles pour un objet du type prédéfini real. Les
paquetages MATH_REAL et MATH_COMPLEX ne font pas partie du standard VHDL de
base, mais sont définis comme des standards séparés.
Il se trouve dans bibliothèque IEEE
Requièrent la clause de contexte
library
IEEE;
use
IEEE.math_real.all;
use
IEEE.math_complex.all;
3.4.6 UPaquetage
NUMERIC_BITU
package NUMERIC_BIT is
type unsigned is array (natural range <>) of bit; --
équiv. à type entier non signé
type signed is array (natural range <>) of bit; --
équiv. à type entier signé
-- opérateurs abs et "-" unaire
-- opérateurs arithmétiques: "+", "-", "*", "/",
rem, mod
-- opérateurs relationnels: "<", ">", "<=",
">=", "=", "/="
-- opérateurs de décalage et rotation: sll, srl,
rol, ror
-- opérateurs logiques: not, and, or, nand, nor, xor,
xnor
-- fonctions de conversion:
-- to_integer(arg)
-- to_unsigned(arg, size)
-- to_signed(arg, size)
end package NUMERIC_BIT;
Utile pour disposer d'opérateurs arithmétiques sur
des opérandes de
types similaires (mais pas équivalents) au type
bit_vector.
Requiert la clause de contexte
library IEEE;
use
IEEE.std_logic_1164.all;
use
IEEE.numeric_bit.all;
Un objet de type (un) signed n'est pas directement compatible
avec un objet de type bit_vector. Une conversion de type est requise:
signal
S1: unsigned (7 downto 0);
signal
S2: bit_vector (7 downto 0);
S1 <=
unsigned (S2);
S2 <=
bit_vector (S1);
3.4.7 UPaquetage
NUMERIC_STDU
package NUMERIC_STD is
type unsigned is array (natural range <>) of std_logic; --
équiv. à type entier non signé
type signed is array (natural range <>) of std_logic; --
équiv. à type entier signé
-- opérateurs abs et "-" unaire
-- opérateurs arithmétiques: "+", "-", "*", "/",
rem, mod
-- opérateurs relationnels: "<", ">", "<=",
">=", "=", "/="
-- opérateurs de décalage et rotation: sll, srl,
rol, ror
-- opérateurs logiques: not, and, or, nand, nor, xor,
xnor
-- fonctions de conversion:
-- to_integer(arg)
-- to_unsigned(arg, size)
-- to_signed(arg, size)
end package NUMERIC_STD;
Utile pour disposer d'opérateurs arithmétiques
sur des opérandes de types similaires (mais pas équivalents) au
type std_logic_vector requiert la clause de contexte
library IEEE;
use
IEEE.std_logic_1164.all;
use
IEEE.numeric_std.all;
Un objet de type (un)signed n'est pas directement compatible avec
un objet de type std_logic_vector. Une conversion de type est requise:
signal S1: unsigned(7 downto 0);
signal S2: std_logic_vector(7 downto 0);
S1 <= unsigned (S2);
S2 <= std_logic_vector (S1);
3.5 Uliste des mots clés en
VHDL [12]
Ci dessous est rassemblé tous les mots
réservés du langage VHDL :
ABS ACCESS AFTER ALIAS ALL AND ARCHITECTURE ARRAY ASSERT
ATTRIBUTE BEGIN BLOCK BODY BUFFER BUS CASE COMPONENT CONFIGURATION CONSTANT
DISCONNECT DOWNTO ELSE ELSIF END ENTITY EXIT FILE FOR FUNCTION GENERATE GENERIC
GUARDED IF IN INOUT IS LABEL LIBRARY LINKAGE LOOP MAP MOD NAND NEW NEXT NOR NOT
NULL OF ON OPEN OR OTHERS OUT PACKAGE PORT PROCEDURE PROCESS RANGE RECORD
REGISTER REM REPORT RETURN SELECT SEVERITY SIGNAL SUBTYPE THEN TO TRANSPORT
TYPE UNITS UNTIL USE VARIABLE WAIT WHEN WHILE WITH XOR.
3.6 U les
littérauxU [12]
n Caractères: `0', `X', `a', `%'
n Chaînes: `'1110101'', `'XX'', `'bonjour'', `'$^&@!''
n Chaînes de bits: B''0010_1101'', X''2D'', O''055''
n Décimaux : 27, -5, 4E3, 76_562, 4.25
n Basés : 2#1001#, 8#65_07#, 16#C5#E+2
3.7 UExemples de quelques petits programmes
écris en VHDLU [11]
3.7.1 U Porte
« additionneur»
opa
opb
cin
cout
sum
UFigure3.1U :
UPorte « additionneur»U
entity add1 is
generic (
TP: time := 0 ns -- temps de propagation
);
port (
signal opa, opb, cin: in bit;
-- opérandes, retenue entrante
signal sum, cout : out bit --
somme, retenue sortante
);
end entity add1;
architecture dfl of add1
is
begin
sum <= opa xor opb xor
cin after TP;
cout <= (opa and opb) or
(opa and cin) or (opb and
cin) after TP;
end architecture dfl;
Ou encore avec un comportement séquentiel
architecture algo of add1
is
begin
process (opa, opb, cin)
variable tmp: integer;
begin
tmp := 0;
if opa = '1' then tmp
:= tmp + 1; end if;
if opb = '1' then tmp
:= tmp + 1; end if;
if cin = '1' then tmp
:= tmp + 1; end if;
if tmp > 1 then
cout <= '1' after TP;
else cout <= '0'
after TP; end if;
if tmp mod 2 = 0
then sum <= '0' after TP;
else sum
<= '1' after TP; end if;
end process;
end architecture algo;
3.4.2 UDeuxième
exempleU : Mémoire Set-Reset
UFigure3.2 :
UMémoire Set-ResetU
Ce deuxième exemple est purement didactique et non
synthétisable. Il modélise une mémoire Set-Reset avec
différenciations des retards à la montée et à la
descente.
entity memoire_rs is
port (s, r: in bit; q, qb :
OUT BIT);
end;
architecture processus of
memoire_rs is
constant Tplh : time := 2
ns;
constant Tphl : time := 1 ns;
signal qi : bit := `0';
signal qbi : bit := `1';
begin
n1 : process
variable qtmp : bit;
begin
wait on s, qi ;
qtmp := s nor qi; -- la primitive
nor
if qtmp /= qbi then --
Test du changement éventuel
if qtmp = `0'
then qbi <= qtmp after Tphl;
else
qbi <= qtmp after
Tplh;
end if;
end if;
end process;
n2 : process
variable qtmp : bit;
begin
wait on r, qbi ;
qtmp := r nor qbi; -- la
primitive NOR
if qtmp /= qi
then -- Test du changement eventuel
if qtmp = `0'
then
qi <= qtmp
after Tphl;
else
qi <= qtmp
after Tplh;
end if;
end if;
end process;
q <= qi;
qb <= qbi;
end;
|