Arithmétique en virgule fixe

Types de données pour travailler avec des nombres réels

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.

Le type 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 nn a pour poids 2n2^n. 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).

Opérations en virgule fixe

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.

Opérations arithmétiques

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

Comparaisons

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

Décalages

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é.

Conversions et redimensionnement

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.