Une fonction Modulo synthètisable

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
============================================

Commentaire sur le VHDL

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.

 

 

Test de la fonction modulo « MOD »

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

Entrées/sorties Xilinx

synthèse VHDL par ISE

Est-ce équivalent de décrire les entrées-sorties uniquement au niveau VHDL et laisser ISE s’occuper de l’implantation complète ou a-t-on intérêt à inclure sois-même dans le projet VHDL des primitives Xilinx ? question sans doute naïve mais suscitée par l’emploi systématique de primitives dans les IP Xilinx

Afin d’apporter des éléments de réponse à cette question, nous allons implanter de deux façons différentes un registre décrit par la spécification d’entité suivante:

ENTITY registre IS
PORT (
entree_d : IN  std_logic_vector(2 DOWNTO 0);  — 3 devraient suffire
horloge  : IN  std_ulogic;          — fan out 3
raz      : IN  std_ulogic;          — fan out 3
sortie   : OUT std_logic_vector(2 DOWNTO 0));
END registre;

La cible technologique est un virtex5.  Un fichier de contrainte ucf a été utilisé pour l’essai.

Première implantation: VHDL seul

Représentée par la premiere architecture:

ARCHITECTURE sans_primitive OF registre IS

BEGIN  — evidente

R1: PROCESS(raz, horloge)
BEGIN  — PROCESS bascule
IF raz = ’1′ THEN
sortie <= (OTHERS => ’0′);
ELSIF rising_edge(horloge) THEN
sortie <= entree_d;
END IF;
END PROCESS R1;

END sans_primitive;

Le résultat est résumé par le schéma technologique suivant

Registre vue technologique

Deuxième implantation mixte VHDL et primitives:

Elle correspond à la deuxième architecture suivante:

– acces aux primitives xilinx
library UNISIM;
use UNISIM.VComponents.all;

ARCHITECTURE mixte OF registre IS

SIGNAL horloge_tmp, raz_tmp : std_ulogic;      — apres buffer
SIGNAL entree_tmp : std_logic_vector(2 DOWNTO 0);  — idem
SIGNAL sortie_tmp : std_logic_vector(2 DOWNTO 0); — avant buffer

BEGIN  — mixte

– registre logique
R2: PROCESS(raz_tmp, horloge_tmp)
BEGIN  — PROCESS bascule
IF raz_tmp = ’1′ THEN
sortie_tmp <= (OTHERS => ’0′);
ELSIF rising_edge(horloge_tmp) THEN
sortie_tmp <= entree_tmp;
END IF;
END PROCESS R2;

– buffers internes

Buf_horloge : bufgp
PORT MAP (    I => horloge,
O => horloge_tmp);

buf_raz: ibuf
PORT MAP (    I => raz,
O => raz_tmp);

boucle: FOR i IN 0 to 2 GENERATE
ibuf_entree: ibuf
PORT MAP (    I => entree_d(i),
O => entree_tmp(i));
obuf_sortie: obuf
PORT MAP (    I => sortie_tmp(i),
O => sortie(i));
END GENERATE;

END mixte;

Conclusion

Après implémentation, on obtient exactement le même résultat avec pour seule différence, c’est la maitrise des noms d’instances comme par exemple:  boucle[1].obuf_sortie

Donc soyons rassuré, à priori ISE sait intercaler automatiquement les primitives d’entrée/sortie et l’écriture du VHDL est beaucoup plus simple en style comportemental que structurel. Nous ne descendrons au niveau primitives que si nous y sommes obligés ou pour contredire le résultat de synthèse mais ceci se produit-il un jour ?

Faire le point

Deux ans et demi que VHDL33 existe.  Une moyenne de 150 visites par jour m’encourage à améliorer encore aussi bien la forme que le fond. Un nouveau look aujourd’hui,  un menu déroulant pour les pages statiques, quelques images et un logo dans le bandeau, voilà pour la forme.

Pour le fond, il y a vraisemblablement des rubriques à compléter. Mais là, un peu d’interactivité serait la bienvenue afin de satisfaire le plus grand nombre. En effet , bien peu de gens me propose des idées, des sujets à traiter.  Je suis tout à fait ouvert et si un sujet est digne d’intérêt général , je peux y consacrer un peu de temps et le publier pour en faire profiter le plus grand nombre.

Vous pouvez soit laisser des commentaires aux articles après vous être inscrit soit me contacter directement à l’adresse suivante:  vhdl33@free.fr

Périphérique Timer 64 bits

Un Timer c’est simple! mais en général, c’est limité à 32 bits. C’est pour cette raison que j’ai mis au point un timer ( en fait un compteur) 64 bits avec commande de capture par programme  et possibilité de lecture en 2 fois 32 bits.

Ce timer est conçu pour être immédiatement intégrable dans un système NIOS Altera ou Xilinx Microblaze ou PowerPC

Dans ces conditions, la capacité du compteur ainsi que sa résolution sont très élevée puisque 2**64 est un nombre considérable.

Vous trouverez tout le matériel (sources , résultat de simulation et petite documentation ici: Timer64

SOC et IP

Bientôt Noël ! C’est le bon moment pour faire un petit cadeau à mes fidèles lecteurs.  Ce qui me reste dans ma hotte, c’est une présentation du monde SOC et IP (dernière mise à jour , début 2009) et surtout une version en français d’un tutoriel NIOS II Altera.

En effet, ma vieille expérience en matière de NIOS ( 1 et 2)  m’a montré que pour chaque nouvelle version logicielle d’Altera, nous était proposé un nouveau tutoriel qui ne correspond jamais au design standard.  Ceci est normal car le fabriquant a besoin de faire la promotion de ses nouveaux produits et on doit d’ailleurs lui être reconnaissant de nous offrir une bonne documentation pour démarrer.

Mais à l’inverse l’utilisateur qui a opté pour une plateforme logicielle à évolution lente doit se donner une méthodologie rigoureuse. La souplesse de Quartus vient encore renforcer ce sentiment. En effet, on peut choisir pour la vue haute (TOP) du projet une description VHDL ou schématique.

C’est pourquoi, le choix que l’on retrouvera dans tous nos travaux pratiques s »appuie sur une description complète de la carte utilisée par un fichier TCL.  Ainsi sera fixé une bonne fois pour toutes le choix du type du composant, les noms et le type des entrées-sorties, les options de compilation éventuelles.  (Voir  Exemple de Fichier TCL)

Pour ceux qui n’ont pas de console TCL (Quartus web edition, je pense), On peut suivre la même démarche en peaufinant un fichier d’affectation des broches.

Histoire ancienne

Compiler du VHDL, c’est implanter de façon puissante ce que l’on appelait autrefois des fonctions logiques combinatoires et/ou  séquentielles.  Sauf que pour le compilateur VHDL la cible n’est pas à proprement parlé une porte mais un élément physique en général de type mémoire (les look-up table pour les FPGA) ou bascule.

Alors est-il encore utile d’enseigner la simplification des fonctions logiques ?  le débat est ouvert car en plus , en général, « à la main » on ne sait simplifier facilement (table de Karnaugh) que des problèmes combinatoires à 6 variables maximum. Le problème d’optimisation de fonctions multiples des mêmes variables est quasi insoluble, bref on est très limité. Mon avis est qu’il faut garder des bases pour introduire à la compréhension des logiciels que l’on va utiliser et c’est tout !

Je pratique les circuits numériques depuis leur début et ai pu suivre et accompagner leur évolution. A la fin des années 60, on faisait encore des circuits logiques  avec des transistors ( je pense aux technologies DTL, TTL, ECL). Le seul outil de conception était le papier et le crayon , et donc les méthodes de simplification de fonction (Karnaugh, Consensus) étaient de la plus haute importance.

Ensuite , sont venus les premiers circuits intégrés, les outils de CAO proposaient comme entrée la schématique et l’on devait déposer une porte , une bascule, un compteur qui allaient exister tel quel.  On ne se privait pas d’ailleurs d’introduire quelques bidouilles comme générer des impulsions calibrées en largeur au moyen d’une porte ET recevant une entrée et la même inversée n fois (équation logique de type A et /A = 0), opération  impossible à faire en synthèse VHDL car tout de suite optimisé comme 0).

C’est dans ce dernier contexte que m’était venu le besoin d’optimiser les circuits et donc de bénéficier d’un logiciel de simplification de fonctions . Ainsi est né FACILOG, une antiquité maintenant mais qui garde l’avantage d’expliciter de façon formelle les équations logique des fonctions combinatoires ou des machine d’états.

Les sources (C) de FACILOG sont disponibles et ce programme ne demande qu’à trouver une autre jeunesse. En particulier à l’époque pas ou peu de graphique, donc l’interface est uniquement texte,  de plus les noms des variables ont été automatisées pour simplifier, bref, on pourrait grandement l’améliorer tout en gardant l’idée de départ. Disposer en quelque sorte d’une calculette dédiée aux circuits logiques.

Tout en un seul fichier

Dans certaines circonstances,  pour une raison de documentation plus lisible, on peut être tenté de placer les informations de placement / routage directement dans le fichier source VHDL au lieu de les fixer dans les outils dédiés.

On perd de ce fait, l’aspect portable du VHDL qui devient dépendant de la cible utilisée. Cela peut cependant être admis , au moins de façon temporaire pour des petits projets non évolutifs.

Le fichier copie.vhd  indique la syntaxe employée pour une entrée et une sortie dans le cas d’un projet  Xilinx ise (pour plus de détails , voir doc Xilinx cgd.pdf page 35).

Avec une syntaxe très proche, on peut faire la meme chose pour un projet Altera / quartus. Voir le fichier copie_altera.vhd

On peut aller plus loin et fixer la place d’un élément ou des contraintes pour le routage.

Bref, avoir tout le projet documenté dans le fichier source VHDL

Picoblaze

Décrire du matériel ou du logiciel est une tache longue qui demande beaucoup de test de validation. Si l’on veut un tant soit peu progresser, il est tout à fait nécessaire d’engranger l’expérience acquise sous forme de modules réutilisables à volonté (c’est le design reuse). On ne fait que redire sous une autre forme la nécessité de structurer les projets.

Parmi les tâches répétitives dans les projets de conception de cartes électroniques, l’interfaçage avec des éléments classiques tels que  écran, clavier, port série etc… sont les plus fréquentes.  Or le niveau de complexité de ces interfaces (un écran LCD est un bon exemple)  demande de mettre en œuvre des temporisations, un séquencement intelligent et un contrôle de l’ensemble qui n’est pas simple. Concevoir le tout, cela revient en quelque sorte à concevoir un microcontroleur spécifique.

Une solution efficace consiste dans ce contexte à utiliser un composant programmable  type microcontroleur 8 bits comparable au pic ( voir article Tp Pic).

Dans cet ordre d’idée, la société Xilinx propose un tel microcontroleur optimisé pour ses séries Spartan et Virtex, c’est le picoblaze. On en trouvera une présentation résumée ici.

Nous avons développé une application d’affichage  de messages sur un écran LCD.   Ce petit projet permet de s’initier au picoblaze en tant que composant programmable. On pourra en particulier juger de la documentation et des sources picoblaze, apprécier l’outil d’assemblage du code, enfin  comparer le résultat à la solution « tout VHDL » en termes de surface occupée mais aussi temps passé au développement et évolution possible.

Signaux virtuels (modelsim)

Nous, pauvres électroniciens, sommes souvent rebelles à ce qui nous semble trop d’informatique. Et pourtant, ce vieux TCL utilisé comme langage de commande dans Modelsim, Quartus , partout où on le souhaite, comme il peut nous simplifier les projets! Parmi ses nombreuses possibilités,  Modelsim offre celle de créer des signaux « virtuels » utiles chaque fois que l’on veut afficher quelque chose de non standard.

C’est le cas lorsqu’on travaille sur un projet comportant un processeur. Si l’on veut visualiser en simulation le bon déroulement d’un programme, il est fastidieux sinon quasiment impossible de se contenter de l’opcode binaire ou hexadécimal. L’outil simulation se présente alors comme passablement inadapté.  Si le code machine est suffisamment structuré en champs de bits, il est par contre possible de se fabriquer un désassembleur qui, appliqué à ce même code, pourra, via un signal virtuel, afficher en clair les mnémoniques. Muni du fichier listing assembleur, on pourra aisément alors se repérer.

Nous en avons un bon exemple dans le fichier virtual.do du projet PIC. On commence (virtual type) par définir un type énuméré dont les 64 éléments sont tous les mnémoniques possibles classés selon leurs 6 bits de codage. Ensuite, on définit un signal virtuel correspondant au champ de ces  6 bits (virtual signal). Enfin on crée un nouveau signal qui va extraire l’élément énuméré (comme un élément de tableau) et donc le mnémonique de l’intruction à afficher (virtual function).