En VHDL, la représentation et la manipulation des nombres entiers s’effectuent
le plus souvent à l’aide des types integer
, signed
et unsigned
.
Les types signed
et unsigned
sont définis comme des vecteurs logiques et
sont plus adaptés lorsque la description d’un circuit utilise les mêmes signaux
dans des opérations arithmétiques et des manipulations de valeurs binaires.
Pour travailler avec des nombres réels en VHDL, il existe plusieurs possibilités :
Paquetage | Types | Définition | Utilisation |
---|---|---|---|
Standard | real |
Intervalle de valeurs | Nombre réel abstrait |
float_pkg |
float |
Vecteur logique | Nombre en virgule flottante |
fixed_pkg |
sfixed , ufixed |
Vecteur logique | Nombre en virgule fixe |
Le type real
fonctionne un peu comme le type integer
: on peut l’utiliser
lorsqu’on ne s’intéresse pas à la façon dont une valeur est codée en binaire.
Mais contrairement au type integer
, les opérations sur le type real
ne sont
généralement pas prises en charge par les outils de synthèse.
On peut utiliser ce type dans les bancs de test en simulation.
Le type float
s’appuie sur la norme IEEE 754,
la plus utilisée aujourd’hui pour représenter des nombres en virgule flottante.
Sur le principe, ce type est utilisable pour décrire et synthétiser un circuit
qui manipule des nombres en virgule flottante.
Cependant, les opérations sur ces nombres sont coûteuses, en temps de calcul
et en ressources matérielles, et peuvent aboutir à des circuits peu performants.
Les types sfixed
et ufixed
permettent de représenter des nombres
signés ou non signés avec une partie entière et une partie fractionnaire
de tailles fixes.
Les valeurs en virgule fixe sont plus limitées, mais beaucoup plus simples à
manipuler que les valeurs en virgule flottante.
Souvent, un circuit en virgule fixe utilise les mêmes opérations
que si l’on travaillait avec des entiers, mais avec des décalages binaires
pour tenir compte de la position de la virgule.
sfixed
Dans ce projet, nous allons utiliser le type signé en virgule fixe sfixed
.
Une valeur en virgule fixe est un vecteur logique dans lequel l’intervalle
des indices spécifie la largeur de la partie entière et de la partie
fractionnaire.
En VHDL, l’astuce consiste à utiliser des indices positifs ou nuls
pour les bits de la partie entière, et des indices négatifs pour les bits de la
partie fractionnaire.
Dans l’exemple ci-dessous, s
possède 4 bits de partie entière (bits 3 à 0)
et 12 bits de partie fractionnaire (bits -1 à -12) :
signal s : sfixed(3 downto -12);
Cette convention est cohérente avec la numération binaire habituelle,
dans laquelle chaque bit d’indice a pour poids .
Dans l’instruction ci-dessous, s
reçoit la valeur 6,625
qui se décompose comme suit :
s <= "0110010100000000";
Indice | 3 | 2 | 1 | 0 | -1 | -2 | -3 | -4 | … | -12 | |
---|---|---|---|---|---|---|---|---|---|---|---|
Poids | -8 | 4 | 2 | 1 | 1/2 | 1/4 | 1/8 | 1/16 | … | 1/4096 | |
Valeur | 0 | 1 | 1 | 0 | . | 1 | 0 | 1 | 0 | … | 0 |
Le type sfixed
peut représenter des nombres positifs et négatifs en
appliquant le principe du complément à deux exactement comme pour les entiers.
Une manière de l’indiquer, comme dans le tableau ci-dessus, est de donner un poids
négatif au bit le plus à gauche.
Dans notre exemple, le signal s
peut prendre des valeurs comprises entre
-8 et 7,9997559 (8-1/4096).
Le paquetage fixed_pkg
que nous fournissons dans le cadre de ce projet est
une version allégée du paquetage officiel de l’IEEE.
Son code source est entièrement disponible dans le fichier fixed_pkg.vhd
de votre dossier de travail.
Vous pouvez l’utiliser en ajoutant la clause suivante dans vos fichiers sources :
use work.fixed_pkg.all;
Dans les tableaux ci-dessous, a
est toujours de type sfixed
tandis que b
peut être de type sfixed
ou integer
.
Lorsque b
est de type integer
, il est automatiquement converti
en virgule fixe avec le même intervalle d’indices que a
.
Il faut donc que le type de a
ait une partie entière assez large pour
contenir b
.
L’addition, la soustraction et la multiplication produisent
toujours un résultat plus large que leurs opérandes.
Si nécessaire, ce résultat peut être redimensionné avec la fonction resize
.
Opération | Résultat |
---|---|
abs a |
La valeur absolue de a |
- a |
L’opposée de a |
a - b |
La différence entre a et b |
a + b |
La somme de a et b |
a * b |
Le produit de a et b |
Ces opérations retournent un résultat de type boolean
.
Opération | Le résultat vaut true si |
---|---|
a = b |
a est égal à b |
a /= b |
a est différent de b |
a > b |
a est strictement supérieur à b |
a >= b |
a est supérieur ou égal à b |
a < b |
a est strictement inférieur à b |
a <= b |
a est inférieur ou égal à b |
Ces opérations traitent une valeur de type sfixed
en tant que vecteur.
Elles peuvent être utilisées pour effectuer des divisions par des puissances de deux.
Opération | Résultat |
---|---|
a srl n |
a décalé de n bits vers la droite, en insérant des zéros à gauche |
a sra n |
a décalé de n bits vers la droite, avec extension du bit de signe |
Dans les deux cas, n
doit être un entier positif ou nul.
Le résultat a le même type que a
.
L’opérateur sra
(Shift Right Arithmetic) préserve le signe du résultat
tandis que srl
(Shift Right Logical) traite a
comme un vecteur logique
non signé.
Dans les expressions ci-dessous, v
peut être de type integer
ou real
;
l
et r
sont des entiers ; a
et s
sont de type sfixed
.
Expression | Résultat |
---|---|
to_signed(a) |
Un vecteur de type signed de même largeur, et avec le même contenu que a (non standard) |
to_unsigned(a) |
Un vecteur de type unsigned de même largeur, et avec le même contenu que a (non standard) |
to_std_logic_vector(a) |
Un vecteur de type std_logic_vector de même largeur, et avec le même contenu que a |
to_real(a) |
La valeur de a convertie en real |
to_string(a) |
Le contenu binaire de a sous la forme d’une chaîne de caractères, avec un point pour séparer la partie entière et la partie fractionnaire |
to_sfixed(v, l, r) |
Le nombre v , converti en sfixed(l downto r) |
to_sfixed(v, s) |
Le nombre v , converti en sfixed avec le même intervalle d’indices que s |
resize(a, l, r) |
Le vecteur a , redimensionné avec l’intervalle d’indices l downto r |
resize(a, s) |
Le vecteur a , redimensionné avec le même intervalle d’indices que s |
Les fonctions to_real
et to_string
peuvent être utilisées dans les bancs de test.