bit
ou std_logic
La valeur d’un bit s’écrit entre apostrophes. Les valeurs disponibles sont les suivantes :
bit |
std_logic |
Signification |
---|---|---|
'U' |
L’état d’un signal non initialisé | |
'0' |
'0' |
La valeur binaire 0 |
'1' |
'1' |
La valeur binaire 1 |
'X' |
Une valeur indéterminée (conflit entre '0' et '1' ) |
|
'Z' |
L’état haute impédance en logique à trois états | |
'L' |
La valeur binaire 0 faible (à travers une résistance de tirage pull-down) | |
'H' |
La valeur binaire 1 faible (à travers une résistance de tirage pull-up) | |
'W' |
Une valeur indéterminée faible (conflit entre 'L' et 'H' ) |
|
'-' |
Une valeur indifférente |
bit_vector
ou std_logic_vector
La valeur d’un vecteur de bits s’écrit entre guillemets. L’ordre des bits entre les guillemets correspond à l’ordre des indices dans le type vecteur utilisé. La base par défaut est le binaire :
signal a : std_logic_vector(0 to 7);
signal b : std_logic_vector(7 downto 0);
...
a <= "11001000"; -- a(0) <= '1'; a(1) <= '1'; a(2) <= '0'; ...
b <= "11001000"; -- b(7) <= '1'; b(6) <= '1'; b(5) <= '0'; ...
Il est également possible d’écrire un vecteur en hexadécimal
en ajoutant la lettre « x
» avant le premier guillemet.
La taille du vecteur doit être multiple de 4 :
signal b : std_logic_vector(7 downto 0);
...
b <= x"C8";
boolean
Le type boolean
définit les valeurs true
(vrai) et false
(faux).
Les valeurs entières s’écrivent par défaut en décimal :
signal value : integer range -40000000 to 39999999;
...
value <= 10427123;
Pour améliorer la lisibilité des grands nombres, il est possible d’insérer des caractères « _ » entre les chiffres sans que cela modifie la valeur totale :
signal value : integer range -40_000_000 to 39_999_999;
...
value <= 10_427_123;
Une valeur entière peut être écrite dans une autre base en respectant la
syntaxe suivante, où base
est un littéral entier écrit en décimal :
base#valeur#
Dans l’exemple ci-dessous, la valeur 10 427 123 a été écrite en hexadécimal (9F1AF3) :
value <= 16#9F1AF3#;
On peut écrire directement une valeur de type tableau comme une liste d’expressions entre parenthèses et séparées par des virgules :
(expression, ... expression)
La notation par association indique explicitement les indices
(à gauche de chaque flèche) et les valeurs (à droite de chaque flèche)
qui leurs sont affectées.
Le mot-clé others
permet d’affecter une valeur à tous les indices qui n’ont
pas été mentionnés précédemment :
(expression => expression, ... others => expression)
Exemples :
type color_vec_t is array(1 to 3) of integer range 0 to 255;
constant PINK : color_vec_t := (255, 192, 203);
constant TURQUOISE : color_vec_t := (1 => 64, 2 => 224, 3 => 208);
constant RED : color_vec_t := (1 => 255, others => 0); -- (255, 0, 0)
constant GREEN : color_vec_t := (2 => 255, others => 0); -- (0, 255, 0)
constant BLUE : color_vec_t := (3 => 255, others => 0); -- (0, 0, 255)
constant WHITE : color_vec_t := (others => 255); -- (255, 255, 255)
constant BLACK : color_vec_t := (others => 0); -- (0, 0, 0)
L’accès à un élément de tableau s’effectue en indiquant la liste des indices entre parenthèses et séparés par des virgules.
nom du tableau(expression, ... expression)
L’accès à un sous-tableau (une tranche) est possible en indiquant des intervalles à la place des indices. Dans l’exemple ci-dessous, nous séparons un vecteur de 32 bits en quatre vecteurs de 8 bits :
signal c : : std_logic_vector(31 downto 0);
signal r, v, b, a : std_logic_vector(7 downto 0);
...
r <= c(31 downto 24);
v <= c(23 downto 16);
b <= c(15 downto 8);
a <= c(7 downto 0);
Comme pour les tableaux, on peut écrire une valeur d’un type structuré comme une liste d’expressions entre parenthèses et séparées par des virgules :
(expression, ... expression)
La notation par association indique explicitement les noms des champs
(à gauche de chaque flèche) et les valeurs (à droite de chaque flèche)
qui leur sont affectées.
Le mot-clé others
permet d’affecter une valeur à tous les champs qui n’ont
pas été mentionnés précédemment, à condition qu’ils soient tous de même type :
(nom => expression, ... others => expression)
Exemple :
type color_rec_t is record
rouge, vert, bleu : integer range 0 to 255;
end record;
constant PINK : color_rec_t := (255, 192, 203);
constant TURQUOISE : color_rec_t := (rouge => 64, vert => 224, bleu => 208);
constant RED : color_rec_t := (rouge => 255, others => 0);
constant GREEN : color_rec_t := (vert => 255, others => 0);
constant BLUE : color_rec_t := (bleu => 255, others => 0);
constant WHITE : color_rec_t := (others => 255);
constant BLACK : color_rec_t := (others => 0);
L’accès à un champ s’effectue à l’aide d’un point comme ceci :
nom de la donnée.nom du champ
Exemple :
signal c : color_rec_t;
signal luminance : integer range 0 to 765;
...
luminance <= c.red + c.green + c.blue;
Les expressions sont évaluées de la gauche vers la droite. Les opérateurs de plus forte priorité sont appliqués en premier. Il est possible d’ajouter des parenthèses autour des sous-expressions lorsque c’est nécessaire pour des questions de priorité, ou pour améliorer la lisibilité.
Dans le tableau ci-dessous, nous avons classé les opérateurs les plus courants par priorité décroissante. Les opérateurs situés sur la même ligne on la même priorité.
Catégorie | Opérateurs |
---|---|
Autres opérateurs | ** , not |
Opérateurs multiplicatifs | * , / , mod , rem |
Signes | + , - |
Opérateurs additifs | + , - , & |
Opérateurs relationnels | = , /= , < , <= , > , >= |
Opérateurs logiques | and , or , xor , nand , nor , xnor |
Cette liste n’est pas exhaustive. Nous n’avons représenté que les principaux opérateurs pris en charge par les outils de synthèse.
Les opérateurs ci-dessous s’appliquent aux booléens et aux valeurs logiques
(bit
, bit_vector
, std_logic
et std_logic_vector
).
Opérateur | Signification |
---|---|
not |
Négation |
and |
Et |
or |
Ou (inclusif) |
xor |
Ou exclusif |
nand |
Non-et |
nor |
Non-ou |
xnor |
Non-ou exclusif |
À l’exception de not
, qui a une priorité plus élevée que les autres,
il n’est pas possible de mélanger des opérateurs logiques dans une même expression.
Dans l’exemple ci-dessous, les parenthèses sont obligatoires :
y <= (a and b) or (c and d);
Les opérateurs ci-dessous s’appliquent aux entiers et aux types vecteurs
signed
et unsigned
.
Opérateur | Signification |
---|---|
+ |
Signe positif ou addition |
- |
Signe négatif ou soustraction |
* |
Multiplication |
/ |
Division |
mod |
Modulo |
rem |
Reste |
** |
Puissance |
Pour synthétiser un circuit, les opérateurs /
, mod
et rem
sont soumis à des restrictions.
Les opérateurs suivants produisent un résultat de type boolean
.
Opérateur | Signification |
---|---|
= |
Est égal à… |
/= |
Est différent de… |
< |
Est strictement inférieur à… |
<= |
Est inférieur ou égal à… |
> |
Est strictement supérieur à… |
>= |
Est supérieur ou égal à… |
Ne pas confondre l’opérateur d’affectation de signal <=
avec
l’opérateur de comparaison « Est inférieur ou égal à… ».
L’opérateur &
sert à concaténer des tableaux.
Il ne faut pas le confondre avec l’opérateur logique and
:
x <= "1100";
y <= "0101";
z <= x & y; -- z vaut "11000101"
t <= x and y; -- t vaut "0100"
Les intervalles sont utilisés dans différentes situations :
for
ou for...generate
.Un intervalle peut prendre l’une des formes suivantes selon que les indices
sont parcourus dans le sens croissant (to
) ou décroissant (downto
) :
expression to expression
expression downto expression
Pour un type tableau ou un objet de type tableau, l’attribut range
retourne l’intervalle de définition des indices.
L’attribut reverse_range
retourne le même intervalle parcouru dans l’ordre inverse.
Dans l’exemple ci-dessous, le type signed_byte_t
a le même intervalle d’indices
que le type byte_t
(7 downto 0).
Le signal n
est de type entier compris entre 0 et 7;
subtype byte_t is std_logic_vector(7 downto 0);
subtype signed_byte_t is signed(byte_t'range);
signal s : signed_byte_t;
signal n : integer range s'reverse_range;
L’appel de fonction s’écrit en indiquant le nom de la fonction, suivi de la liste des arguments entre parenthèses et séparés par des virgules.
nom de la fonction(expression, ... expression)
La notation par association fait correspondre chaque nom de paramètre avec sa valeur :
nom de la fonction(nom de paramètre => expression, ... nom de paramètre => expression)
Une expression qualifiée permet de lever une ambiguïté sur le type du résultat d’une expression. Elle s’écrit de la manière suivante :
nom de type'(expression)
nom de type'valeur de type tableau
nom de type'valeur de type structuré
Par exemple, à première vue, il n’est pas possible de savoir si "0011"
est de type bit_vector
ou std_logic_vector
.
De même, l’expression (50, 10, 30)
peut aussi bien être de
type color_vec_t
que de type color_rec_t
, ou encore de n’importe quel
autre type tableau d’entiers.
Lorsque c’est nécessaire, on peut écrire, par exemple :
std_logic_vector'("0011")
color_rec_t'(50, 10, 30)
Dans l’exemple ci-dessous, le tableau (r, v, b)
n’est pas affecté
à un signal ou une variable.
Son type ne peut pas être identifié avec certitude.
type color_enum_t is (NOIR, ROUGE, VERT, BLEU, JAUNE, MAGENTA, CYAN, BLANC);
signal c : color_enum_t;
signal r, v, b : std_logic;
...
with (r, v, b) select
c <= NOIR when "000",
ROUGE when "100",
VERT when "010",
BLEU when "001",
JAUNE when "110",
MAGENTA when "101",
CYAN when "011",
BLANC when others;
On peut alors écrire :
with std_logic_vector'(r, v, b) select
...
Une conversion de type permet de traiter une valeur d’un certain type comme si elle était d’un autre type, à condition que ces deux types soient compatibles. En VHDL, la conversion de type ressemble à un appel de fonction dans lequel, à la place d’un nom de fonction, on indique le nom du type de destination :
nom de type(expression)
Par exemple, le paquetage numeric_std
définit les types signed
et unsigned
comme des sous-types de std_logic_vector
.
Les opérations arithmétiques définies sur les types signed
et unsigned
ne sont pas applicables directement aux valeurs de type std_logic_vector
,
pour lesquelles on ne sait pas s’il faut appliquer les règles de calcul pour des
nombres signés ou non signés.
Dans l’exemple ci-dessous :
+
n’est pas défini pour le type std_logic_vector
.+
pour le type signed
,
mais son résultat est de type signed
et ne peut pas être affecté à s
qui est de type std_logic_vector
.std_logic_vector
avant de l’affecter à s
.signal a, b, s : std_logic_vector(7 downto 0);
...
s <= a + b; -- Incorrect (1)
s <= signed(a) + signed(b); -- Incorrect (2)
s <= std_logic_vector(signed(a) + signed(b)) -- Correct (3)
Une fonction de conversion réalise une transformation d’une valeur d’un certain type en une valeur d’un autre type incompatible avec le premier.
Par exemple, le type signed
et le type integer
sont incompatibles :
le premier est un type tableau tandis que le second est défini comme un intervalle
de valeurs.
Pour effectuer des conversions entre vecteurs et entiers,
ou entre vecteurs de même nature, le paquetage numeric_std
définit les fonctions
suivantes :
Fonction | Type de x |
Type du résultat |
---|---|---|
to_integer(x) |
signed ou unsigned |
integer |
to_signed(x, n) |
integer |
signed(n - 1 downto 0) |
to_unsigned(x, n) |
integer |
unsigned(n - 1 downto 0) |
resize(x, n) |
signed ou unsigned |
signed(n - 1 downto 0) ouunsigned(n - 1 downto 0) |
Les attributs permettent d’obtenir des informations supplémentaires sur un élément. La syntaxe générale d’un attribut est :
objet'nom de l'attribut
objet'nom de l'attribut(expression)
Dans cette section, nous nous intéressons uniquement aux attributs qui sont acceptés par les outils de synthèse.
Les types scalaires sont les types entiers
et les types énumérés.
Pour un type scalaire T
, VHDL définit les attributs suivants :
Attribut | Type du résultat | Valeur |
---|---|---|
T'left |
T |
La valeur la plus à gauche de son intervalle de définition, ou la première valeur pour un type énuméré. |
T'right |
T |
La valeur la plus à droite de son intervalle de définition, ou la dernière valeur pour un type énuméré. |
T'low |
T |
La plus petite valeur de ce type. |
T'high |
T |
La plus grande valeur de ce type. |
T'ascending |
boolean |
true si l’intervalle des valeurs est croissant, false s’il est décroissant. |
T'pos(x) |
integer |
La position de la valeur x . |
T'val(n) |
T |
La valeur située en position n . |
T'succ(x) |
T |
La valeur immédiatement supérieure à x . |
T'pred(x) |
T |
La valeur immédiatement inférieure à x . |
T'leftof(x) |
T |
La valeur située à gauche de x . |
T'rightof(x) |
T |
La valeur située à droite de x . |
Comme les types entiers peuvent être définis avec des intervalles croissants
(to
) ou décroissants (downto
),
ces attributs doivent distinguer deux systèmes de classement selon que l’on
s’intéresse aux valeurs (low
, high
, pred
, succ
) ou à l’ordre dans
lequel le type est défini (left
, right
, leftof
, rightof
).
Les attributs pos
et val
permettent d’effectuer des conversions
entre types énumérés et entiers :
type color_enum_t is (BLACK, RED, GREEN, BLUE, YELLOW, MAGENTA, CYAN, WHITE);
signal c1, c2 : color_enum_t;
signal n1, n2 : natural range 0 to 7;
...
n1 <= color_enum_t'pos(c1):
c2 <= color_enum_t'val(n2);
Cest attributs s’appliquent aussi bien aux types tableaux qu’aux valeurs
de type tableau.
Pour les tableaux multidimensionnels, la plupart des attributs acceptent
un paramètre n
qui indique le numéro de la dimension (1 pour la dimension la plus à gauche).
Ce paramètre peut être omis pour les tableaux à une dimension :
type vec3d_t is array(0 to 2) of integer;
-- Les deux écritures suivantes sont équivalentes
constant M : positive := vec3d_t'length;
constant N : positive := vec3d_t'length(1);
Attribut | Type du résultat | Valeur |
---|---|---|
A'left(n) |
integer |
L’indice le plus à gauche pour la dimension n . |
A'right(n) |
integer |
L’indice le plus à droite pour la dimension n . |
A'low(n) |
integer |
L’indice le plus petit pour la dimension n . |
A'high(n) |
integer |
L’indice le plus grand pour la dimension n . |
A'ascending(n) |
boolean |
true si l’intervalle des indices pour la dimension n est croissant, false sinon. |
A'length(n) |
integer |
La taille du tableau pour la dimension n . |
A'range(n) |
integer |
L’intervalle des indices pour la dimension n . |
A'reverse_range(n) |
integer |
L’intervalle des indices pour la dimension n , parcouru dans le sens inverse. |
A'element |
Type | Le type des éléments du tableau (VHDL-2002 ou versions ultérieures). |
La plupart des attributs disponibles pour les signaux ne sont utilisables qu’en simulation. Le seul attribut reconnu par les outils de synthèse est :
Attribut | Type du résultat | Valeur |
---|---|---|
s'event |
boolean |
true si s vient de changer de valeur, false sinon. |