Mon ancien collègue et compère Patrice Nouel m'a demandé de sauvegarder les billets de son blog vhdl33 qu'il ne maintient plus. Voici donc quelques billets intéressants reproduits ci-après :,
Test de la fonction modulo « MOD » 04/04/11
Lorsqu’elle s’applique à des nombres entiers positifs, la fonction « modulo »
est simple à comprendre. Il s’agit du reste de la division d’un dividende par
un diviseur, de telle sorte qu’on puisse écrire:
Modulo = dividende – partie entière de (dividende / diviseur),
avec dans ce cas modulo < diviseur
voir à ce sujet: modulo (informatique) wikipedia
En écriture VHDL, on dispose de cette fonction de multiples fois en surcharge
dans les bibliothèques telles que ieee.numeric_std et la syntaxe est par exemple
:
Modulo <= dividende MOD quotient;
Avec des types non signés ou natural, on va ainsi
constater que : 200 Mod 200 retourne 0, mais que 210
MOD 200 retourne 10.
Le cas des nombres entiers signés est plus délicate
et il est bon de faire un petit programme de test afin de se faire une idée
de la façon dont est calculé le modulo.
Le fichie test_modulo.vhd permet de mieux cerner le fonctionnement
du modulo.
On y constate, en particulier que le modulo VHDL est toujours du même
signe que le diviseur
ainsi : 2444 MOD 200 retourne 44 mais 2444 MOD
-200 reourne -44.
La fonction MOD n’est pas reconnue synthétisable telle quelle sauf si le quotient
est une puissance de 2 car cette opération revient à un décalage de bits. Ainsi
dividende MOD 128 est synthétisable. L’opération équivalente étant de
ne garder que les 7 bits de poids faible de dividende. Ainsi 232 MOD 128 = 232
-128 = 104, opération qui ne coute rien en termes de ressource lors de la synthèse.
Comme il a été expliqué dans l’article précédent, la fonction VHDL « MOD »
correspondant au calcul du modulo n’est pas reconnue comme synthètisable dans les outils courants comme ISE. Il est donc
nécessaire de créer une telle fonction à partir d’autres fonctions qui le
sont. Nous avons choisi la multiplication qui est parfaitement réalisée par
un bloc DSP.
On limite le problème à des nombres non signés. Le diviseur est en principe
une constante de N2 bits, le dividende un nombre de N1 bits. On cherche le
modulo par la relation:
dividende = quotient *
diviseur + modulo
ou modulo = dividende – partie_entiere
(dividende /diviseur)
On procède par dichotomie sur le quotient. On propose une succéssion de quotients jusqu’à ce que dividende –
quotient * diviseur soit inférieur à diviseur. La différence est
alors le modulo cherché.
Avec cette méthode, le temps de calcul en nombre de cycles est en général
de N1 – N2 + 1 .
Il tombe à 1 cycle si le dividende = 0, et est inférieur si le quotient est
apparu plus tôt dans la séquence. Afin de réduire ce temps de cycle, on prendra
bien soin d’ajuster N1 au minimum requis, pour N2 (le diviseur) on doit impérativement
avoir un ’1′ en MSB afin de n’avoir que des bits « utiles.
Le fichier source
et son fichier test
apportent toutes les précisions nécessaires.
A titre d’exemple , voici un extrait du rapport
de synthèse sur une cible Virtex.
Cell Usage : # BELS : 325 # GND : 1 # INV : 4 # LUT2 : 37 # LUT3 : 27 # LUT4 : 34 # LUT5 : 55 # LUT6 : 23 # MUXCY : 84 # VCC : 1 # XORCY : 59 # FlipFlops/Latches : 59 # FD : 23 # FDR : 35 # FDRS : 1 # Clock Buffers : 1 # BUFGP : 1 # IO Buffers : 42 # IBUF : 33 # OBUF : 9 # DSPs : 1 # DSP48E : 1 ============================================
Pour le choix du diviseur rentrant dans le calcul
du modulo, nous l’avons voulu constant et avons donc déclaré une constante
générique:
GENERIC( N1 : natural
:= 24; — Nombres
de bits dividende
divisor : unsigned(7
DOWNTO 0) :=x »C8″ ); — 200 et MSB = ’1′
On veut absolument que le MSB soit 1 ce qui fait dépendre le nombre
de bits de la valeur de la constante. On voit très bien que cette écriture
n’est pas satisfaisante car la constante ne pourra être modifiée que dans
la gamme 128 à 255 puisqu’au delà il faut changer le nombre de bits du diviseur
et donc modifier la spécification d’entité.
Une solution alternative serait de définir une constante générique N2 , nombre de bits du diviseur et du modulo et de définir
un port d’entree
divisor: unsigned(N2-1 DOWNTO 0), mais alors il faudra de l’extérieur assurer
que la valeur d’entrée a bien un MSB = ’1′. On a juste repoussé le problème.