Option : Génération de code VHDL

 

La version  MUSTIG munie de l'option VHDL est une version étendue de MUSTIG. Son fonctionnement est absolument identique à la version standard de MUSTIG (voir manuel). La seule différence visible est la présence d'un menu “VHDL” qui permet de demander la génération le code VHDL de la partie du graphe désirée.

 

 

Principe

 

On utilise tout d'abord MUSTIG comme outil de simulation d'un dispositif avant sa réalisation. Pour cela, on décrit ce dispositif par un graphe MUSTIG, mis à l'intérieur d'une "macro". Pour vérifier son fonctionnement, on construit un graphe MUSTIG qui simule l'environnement de ce dispositif : il crée des signaux de tests et analyse les sorties du dispositif.

Ensuite,  quand la simulation est satisfaisante,  on utilise le transcodeur VHDL pour créer une description en langage VHDL de la macro MUSTIG qui représente le dispositif. Cette description est une description structurelle, qui est apte à servir d'entrée à un outil de synthèse de ce dispositif.

En plus de cette description VHDL du dispositif, MUSTIG peut fournir un fichier VHDL de test ainsi que des fichiers contenant les valeurs numériques des signaux d'entrée. Ces fichiers, ajoutés à la description du dispositif et à la description des éléments de base, permet de refaire sur un simulateur VHDL une simulation dans des condition exactement identiques à celles de la simulation MUSTIG et de vérifier l'identité des résultats.

Schématisation du processus de simulation MUSTIG puis VHDL.

 a) La macro "Filtre" est construite et testée en MUSTIG.

 b) le transcodage VHDL fournit des fichier utilisé par le simulateur VHDL.

 c) il est possible de comparer avec MUSTIG les résultats des deux simulations.

 

La description du dispositif utilise comme éléments des "composants" correspondants à des "briques de base", qui sont des macros MUSTIG prises dans une bibliothèque spéciale, qui ont servi à construire la macro décrivant le dispositif avec MUSTIG. Il est possible pour l'utilisateur d'étendre cette bibliothèque, à condition d'écrire également sa description VHDL pour pouvoir effectuer la simulation VHDL.

 

 


Utilisation

 

Contraintes sur le graphe MUSTIG

La partie du graphe à transcoder doit être sous forme de macro, elle sera appelée ci-après : macro source. Elle ne doit contenir que des opérateurs pris dans la Bibliothèque VHDL. Il est obligatoire de mettre des étiquettes (cf manuel), de noms différents, sur chaque borne de la clôture intérieure de la macro source.

Les étiquettes des bornes et le nom de la macro source ne doivent pas être des mots clés du langage VHDL. Lors des tests, MUSTIG fait référence aux mots clés VHDL'92.

Le transcodage VHDL fonctionne pour des signaux d'entrée dépendant, au plus, d'une variable  (ce sont ces signaux qui fabriqueront les fichiers de stimuli). Il est nécessaire de préciser juste après le nom de la macro source la  variable représentant le temps "vrai" ("t" par défaut). Cette dernière est considérée de longueur infinie pendant le transcodage VHDL, même si elle est de longueur finie dans la simulation MUSTIG.

 

Attention: si votre macro source ne comporte pas d'opérateurs dépendant de la variable VHDL, vous devrez alors mettre dans la macro source un tel opérateur (par exemple: "Retard/t") sans le connecter à votre graphe et vous pourrez alors préciser le nom de la variable VHDL sinon le message d'erreur "trop de variables" apparaît.

Le type de données manipulées par MUSTIG dans la partie du graphe transcodé en VHDL doit être "flottant 4 octets" (valeur par défaut de MUSTIG) ou "entier à précision variable"(disponible en option).

 

Activation du transcodage VHDL

Avant la génération VHDL, il est obligatoire de calculer le graphe, par exemple en demandant la visualisation des sorties. Sinon, un message d'erreur y invite.

On sélectionne la macro à transcoder en VHDL (appelée macro source), puis on choisit Lancer VHDL dans le menu  VHDL, et alors le dialogue VHDL apparaît à l'écran. Ce dialogue fait apparaître toutes les options disponibles pour le transcodage. Modifier, si nécessaire certains paramètres.

Le transcodage est lancé par l'action de l'un des trois boutons "Generate..."

-  Generate BEHAVIOR permet de créer le fichier qui décrit l'entité du composant ainsi que le fichier qui contient son architecture.

-  Generate TEST-BENCH permet de créer les fichiers de stimuli ainsi que le fichier qui décrit l'entité et l'architecture de test.

-  Generate both réalise la génération BEHAVIOR et TEST-BENCH.

 

Paramètres du transcodeur VHDL :

Les 3 premiers champs de ce dialogue sont des paramètres communs entre la génération BEHAVIOR  et la génération TEST-BENCH .

-  Const. as "Generic": si cette case est cochée, les entrées de la macro à transcoder qui ne dépendent pas du temps seront considérées comme paramètres "generic" en VHDL. Sinon, elles correspondent à un port.

-  Clock Name : <nom de l'horloge>, valeur par défaut  "CLK" . C'est le nom donné au signal d'horloge dans la simulation VHDL.

-  Library : <nom de la bibliothèque VHDL liée à MUSTIG>, valeur par défaut : "MUSTIG_LIB"

 

Les 6 champs suivants concernent uniquement la génération BEHAVIOR.

-  Entity Name : <nom de l'entité du composant>, valeur par défaut : le nom de la macro source. Exemple: "Filtre"

-  Entity File Name : <nom du fichier contenant l'entité du composant>, valeur par défaut : le nom de la macro source en minuscules, suivi de la chaîne ".vhd". Exemple: "filtre.vhd"

-  Architecture Name : <nom de l'architecture du composant>, valeur par défaut : "MUSTIG"

-  Architecture File Name : <nom du fichier contenant l'architecture du composant>, valeur par défaut : le nom de l'entité en minuscules, suivi du caractère '_' suivi du nom de l'architecture en minuscules, suivi de la chaîne ".vhd". Exemple: "filtre_mustig.vhd"

-  Operator Unit  Names : <nom des paquetages (ou unités) définissant les opérateurs>, valeur par défaut : "PROCEDURES_PKG"

-  Operator File  Names : <nom des fichiers contenant les unités définissant les opérateurs>, valeur par défaut : nom des unités en minuscules, suivis de la chaîne "_.vhd". Exemple:  "procedures_pkg_.vhd"

 

Enfin les autres champs définissent le contexte génération TEST_BENCH.

-  Period Unit : <unité de temps de la période>, valeur par défaut : NS. L'unité de temps est une valeur prise dans l'ensemble suivant: MIN, SEC, MS , US, NS, FS (la valeur de la période d'horloge est mise à la valeur du pas d'échantillonnage de la variable vhdl de MUSTIG - modifiable par le module Pas)

-  Test Entity Name : <nom de l'entité de test>, valeur par défaut : "TEST"

-  Test Architecture Name : <nom de l'architecture de test>, valeur par défaut : "BENCH"

-  VHDL File Name : <nom du fichier contenant l'entité vide et l'architecture de test>, valeur par défaut : le nom de l'entité de test en minuscules, suivi de la chaîne ".vhd". Exemple: "test.vhd"

-  I/O Unit Name : < nom du paquetage d'acquisition et de restitution des stimuli>, valeur par défaut : "IO_PKG". Il doit se trouver dans la bibliothèque dont le nom est indiqué au champ "Library".

 

Tous ces paramètres peuvent être modifiés.  L'action du bouton "Default values" réinitialise tous les paramètres aux valeurs par défaut comme indiqué ci-dessus.

Ce dialogue apparaît avec des valeurs par défaut si elles n'ont jamais été

modifiées, sinon les propres valeurs de l'utilisateur sont sauvegardées (dans le fichier MUSTIG_VHDL.prf  et sont restituées lors de l'affichage du dialogue.

 


 

Approfondissement de la génération VHDL

 

Nommage du composant et de ses ports

En VHDL, la macro source est traduite en une entité et une architecture. Ce couple (entité-architecture) est défini en composant dans l'architecture de test.

Chaque borne de la macro source correspond à un port du composant (ou à un paramètre "generic" si l'entrée ne dépend pas du temps et que l'option "Constants as generic" est validée. Les ports du composant déclarés dans l'architecture de test sont définis dans l'entité. L'algorithme de calcul de ce composant est défini dans l'architecture.

Les étiquettes (obligatoires) des bornes de la clôture intérieure de la macro source nomment ainsi tous les ports. Ces étiquettes sont donc les noms génériques des ports du composant réalisé. On rappelle que chaque borne de la clôture intérieure de la macro source doit avoir une étiquette, que cette étiquette ne doit pas déjà être utilisée et qu'elle ne doit pas correspondre à un mot clé du langage VHDL.

Si ces conditions ne sont pas respectés, MUSTIG affichera alors un message d'erreur et arrêtera la génération de code VHDL.

Par défaut (voir précédemment la description du dialogue) le nom de la macro est utilisé pour nommer le composant. Il sera donc facile, en modifiant le nom de la macro source et le graphe MUSTIG à l'intérieur de cette macro, de générer différentes architectures de composants sans modifier le contexte de test.

Les étiquettes sur les bornes de la clôture extérieure de la macro source sont facultatives. Cependant si elles existent, elles aussi ne doivent pas être des étiquettes déjà utilisées ou des mots clés du langage VHDL. De plus, si elles existent, elles sont utilisées pour nommer les signaux d'entrée du composant et pour nommer les fichiers de stimuli lors de leur génération, sinon ce sont les étiquettes des bornes de l'intérieur de la macro source qui sont utilisées.

Lors de la génération de l'architecture de test, pour chaque borne d'entrée de la macro source, dépendant de la variable vhdl, on déclare un signal d'entrée (nommé comme ci-dessus) et un fichier de stimuli associé. Ce dernier est alors créé. Son nom est composé de l'étiquette de la borne mis en minuscules, suivie de la chaîne ".dat" et précédé du nom de la macro à transcoder. Pour les autres bornes (ne dépendant pas de la variable vhdl), on déclare des signaux : si le signal est scalaire, il est alors nommé avec une étiquette choisie comme ci-dessus, tandis que si le signal dépend d'une autre variable, il est indexé (voir la méthode d'indexation plus loin). Ces signaux sont initialisés par les valeurs fournies par le graphe MUSTIG en amont de la macro.

Il suffit donc de changer les étiquettes des bornes d'entrée dépendant de la variable VHDL pour générer des noms de fichiers de stimuli différents.

 

Nommage des signaux internes

Les étiquettes sur les bornes de clôtures internes à la macro source sont utilisées si elles existent pour nommer les signaux intermédiaires. Si un signal se propageant d'une borne de sortie d'un module à une borne d'entrée d'un autre module traverse plusieurs bornes étiquetées, l'étiquette retenue est celle qui se trouve la plus extérieure par rapport à la borne de sortie du signal considéré. La notion d'extérieur est comptabilisée telle que lorsqu'on sort d'une clôture cette notion est augmentée d'une unité tandis que lorsqu'on entre dans une clôture cette notion est diminuée d'une unité.

Si un signal intermédiaire peut être nommé grâce à une étiquette, alors son nom devient : nom de l'étiquette, suivi du caractère "_", suivi de la valeur du compteur de nombre de signaux. Par exemple : "PI_4". Sinon, s'il n'y a pas d'étiquette pour nommer ce signal, il est alors numéroté et son nom devient : la chaîne "Si", suivi de la valeur du compteur du nombre de signaux. Par exemple : "Si8".

Si un signal MUSTIG dépend d'une variable non VHDL, il y a création de N signaux VHDL (N étant la taille de ce signal MUSTIG). Pour différencier ces N signaux VHDL ils sont indexés. Leurs noms sont crées avec la méthode détaillée ci-dessus, puis complété par le caractère '_', suivi du numéro de l'indice. L'indice parcourt les entiers naturels de 0 à N-1.

Si un signal dépend uniquement de la variable VHDL ou s'il est constant, on ne l'indexe pas.

Ce qui donne par exemple "Si2" ou "Sortie_filtre_7" pour un signal constant ou dépendant de la variable VHDL et "Si4_2" ou "Coef_0" pour les autres.

Remarques

Il est plus judicieux de mettre des étiquettes sur les bornes de sortie des opérateurs VHDL : le graphe est alors plus "parlant".

La chaîne "TST" est une étiquette toujours utilisée dans la définition et configuration du composant à tester. Donc ce mot se rajoute aux mots réservés qu'il ne faut pas réutiliser.

 

Considérations sur le constantes

Une constante est une valeur qui ne dépend pas de la variable "temps". Ce peut être un scalaire ou un signal qui dépend d'une autre variable que la variable temporelle. Cette constante peut être fournie par un module "Val", ou bien être le résultat d'un graphe MUSTIG. Ce graphe de calcul de la constante peut être placé à l'intérieur de la macro source, à condition de ne pas utiliser de valeurs extérieures à la macro. Dans ce cas, il ne fait pas partie du graphe transcodé en VHDL. Sa sortie sera évalué par MUSTIG, et seule la valeur résultante apparaîtra, comme une constante numérique, dans le code VHDL.

La constante peut être appliquée également à une borne d'entrée  de la macro source. Dans ce cas, deux fonctionnements sont possibles, en fonction du choix fait pour l'option Const. as "Generic" (voir ci-dessus)

-  Si l'option Const. as "Generic" n'est pas cochée, elle sera considérée comme un port, comme si elle n'était pas contante.

-  Sinon (cochée, par défaut) , cette constante sera mise comme un paramètre générique. Mais attention, dans la version actuelle du transcodeur, il n'est pas possible, à l'intérieur de la macro source, de faire des calculs  sur ce paramètre en lui conservant son caractère de constante.

 

Création des Bibliothèques VHDL et des paquetages correspondants :

La partie du graphe transcodée en VHDL ne doit contenir que des opérateurs spécifiques. Ils seront stockés dans une bibliothèque. La bibliothèque Bib_VHDL fournie en est un exemple. Ces opérateurs sont mis sous forme de macro dont le nom doit commencer par la chaîne "VHDL_", suivie du nom de la procédure correspondante définie dans le paquetage.

L'utilisateur peut lui-même enrichir la bibliothèque MUSTIG des éléments de base utilisés pour construire la macro à transcoder.  Il faut alors modifier la paquetage VHDL correspondant (par défaut "PROCEDURES_PKG" dans le fichier "procédures
_pkg_.vhd"). Notons que le fichier "procedures_pkg_.vhd" ne contient que la vue externe de ces procédures. Pour pouvoir effectuer une simulation, il faudra également en faire une description interne. Mais cette description externe doit être à jour  dans tous les cas, même si l'on ne désire pas réaliser de simulation VHDL car le transcodeur VHDL de MUSTIG l'utilise.

Les paramètres des procédures VHDL doivent toujours être des signaux. Leur type peut être :

-  REAL pour des signaux MUSTIG de type flottant

-  STD_ULOGIC_VECTOR pour des signaux de  MUSTIG de type "entier à précision variable".

Le fichier doit également comporter la procédure DELAY (bien qu'elle ne corresponde pas à un module spécifique VHDL de MUSTIG). Elle correspond à un bouclage (au sens MUSTIG, c'est  à dire à un "paquet") sur la variable temps ou à la macro "Retard/t" de la bibliothèque MUSTIG.

La procédure DELAY doit être :

procédure DELAY (signal CLK : in BIT; signal IN1 : in REAL; signal OUT1 : out REAL; signal INIT : in REAL);

Le signal INIT est utilisé pour l'initialisation de la sortie OUT1 avant qu'un événement arrive sur l'entrée IN1.

Dans la création du code VHDL, les signaux de sortie ne sont pas initialisés. Il revient donc au créateur des paquetages de le faire s'il juge que l'initialisation par défaut de VHDL peut entraîner des insatisfactions.

Sous MUSTIG, les macros VHDL doivent correspondre exactement à leur description faite dans le paquetage. C'est à dire, les noms des bornes d'entrée et des bornes de sortie doivent être identiques, le nom de la macro VHDL doit être celui de la procédure correspondante, précédé de la chaîne "VHDL_". C'est au créateur du paquetage VHDL et de la bibliothèque MUSTIG associée de vérifier la concordance entre les fonctionnalités des macros MUSTIG et celles des modules VHDL. La vérification faite par le transcodeur ne porte que sur les interfaces.

 

Exemples de transcodage

 

Filtre récursif du premier ordre (flottant)

Coefficient interne

Un des graphes MUSTIG les plus simple pour mettre un filtre en oeuvre est le suivant. Il est bien évident qu'en pratique en pourra le tester avec des signaux plus complexes, et analyser sa sortie avec des traitements plus sophistiqués.

L'intérieur de la macro "FiltreRII1" correspond au graphe suivant. Elle utilise les macros "VHDL_ADD" et VHDL_MULT", pris dans la bibliothèque "Bib_VHDL" et la macro "Retard/t" qui peut provenir de la bibliothèque principale de MUSTIG.

Commençons par observer les fichiers produits par la commande VHDL de MUSTIG "Generate TEST BENCH". Ces sorties ne dépendent pas du graphe de description du filtre situé à l'intérieur de la macro "FiltreRII1", sauf en ce qui concerne les noms des bornes d'entrée et sortie qui sont donnés par des étiquettes MUSTIG internes.

 

Le fichier  "filtrerii1.vhd" décrit la vue externe du filtre

entity FiltreRII1 is

library IEEE;

use IEEE.STD_LOGIC_1164.all;

port (CLK : in BIT;

      Entree : in REAL;

      Sortie : out REAL);

end;

On voit que les deux bornes de la macro MUSTIG correspondent à deux "ports" VHDL. On trouve dans ce fichier, comme dans tous autres fichiers VHDL générés, une référence à une bibliothèque VHDL "IEEE" qui est nécessaire pour la déclaration des types "BITs" utilisés plus loin.

Le fichier test.vhd contient le code VHDL de simulation de ce filtre.

entity TEST is end TEST;

library IEEE;

use IEEE.STD_LOGIC_1164.all;

library MUSTIG_LIB;

use MUSTIG_LIB.IO_PKG.all;

use STD.TEXTIO.all;

architecture BENCH of TEST is

      constant PERIOD : TIME := 1.000000e+00 NS;

      component FiltreRII1

      port (CLK : in BIT;

            Entree : in REAL;

            Sortie : out REAL);

      end component;

      for TST : FiltreRII1 use entity WORK.FiltreRII1(MUSTIG);

      signal CLK : BIT;

      signal Entree : REAL;

      signal Sortie : REAL;

      file F_ENTREE : TEXT is in "filtrerii1_entree.dat";

      file F_SORTIE : TEXT is out "filtrerii1_sortie.dat";

begin

      CLK_GENERATOR : CLK <= not CLK after PERIOD/2;

      READ (F_ENTREE,CLK,Entree);

      TST : FiltreRII1 port map (CLK,Entree,Sortie);

      WRITE (F_SORTIE,CLK,Sortie);

end;

Ce fichier fait référence au fichier filtre "filtrerii1_entree.dat" qui contient la liste des valeurs du signal appliqué au filtre lors de la simulation MUSTIG. Ce fichier est lu par une procédure  "READ".

 1.00000000e+00

 1.00000000e+00

 1.00000000e+00

 1.00000000e+00

 1.00000000e+00

 1.00000000e+00

 1.00000000e+00

 1.00000000e+00

 1.00000000e+00

 1.00000000e+00

 0.00000000e+00

 0.00000000e+00

 0.00000000e+00

 0.00000000e+00

 0.00000000e+00

 0.00000000e+00

 0.00000000e+00

 0.00000000e+00

 0.00000000e+00

 0.00000000e+00

Symétriquement, une procédure "WRITE" écrit la sortie du filtre pendant la simulation VHDL. Le fichier "filtrerii1_sortie.dat" peut être relu ensuite par MUSTIG.

La description interne du filtre, produite par la commande VHDL de MUSTIG "Generate BEHAVIOR" est contenue dans le fichier "filtrerii1_mustig.vhd"

library IEEE;

use IEEE.STD_LOGIC_1164.all;

library MUSTIG_LIB;

use MUSTIG_LIB.SYNTHESIS_PKG.all;

use MUSTIG_LIB.PROCEDURES_PKG.all;

architecture MUSTIG of FiltreRII1 is

      signal Si1 : REAL :=  0.00000000e+00;

      signal Si2 : REAL;

      signal Si3 : REAL :=  6.99999988e-01;

      signal Si4 : REAL;

      signal Si5 : REAL;

      signal Si6 : REAL;

begin

      M1 : MULT(IN2 => Si3,IN1 => Si2,OUTS => Si4);

      A2 : ADD(IN2 => Si4,IN1 => Entree,OUTS => Si5);

      Sortie <= Si5;

      F3 : DELAY(CLK,Si5,Si2,Si1);

end MUSTIG;

Pour un graphe un peu compliqué, il peut être difficile de vérifier la concordance du code VHDL et de graphe MUSTIG. Si cela est nécessaire, il est commode de mettre des étiquettes en divers points du graphe, les noms de ces étiquettes servirons à nommer les signaux VHDL. Ainsi, si on ajoute des étiquettes à la description du filtre :

 

On obtient un code VHDL plus lisible :

library IEEE;

use IEEE.STD_LOGIC_1164.all;

library MUSTIG_LIB;

use MUSTIG_LIB.SYNTHESIS_PKG.all;

use MUSTIG_LIB.PROCEDURES_PKG.all;

architecture MUSTIG of FiltreRII1 is

      signal Si1 : REAL :=  0.00000000e+00;

      signal Si2 : REAL;

      signal Coefficient_3 : REAL :=  6.99999988e-01;

      signal Reboucle_4 : REAL;

      signal Somme_5 : REAL;

      signal Si6 : REAL;

begin

      M1 : MULT(IN2 => Coefficient_3,IN1 => Si2,OUTS => Reboucle_4);

      A2 : ADD(IN2 => Reboucle_4,IN1 => Entree,OUTS => Somme_5);

      Sortie <= Somme_5;

      F3 : DELAY(CLK,Somme_5,Si2,Si1);

end MUSTIG;

Ce fichier comporte une référence à la librairie VHDL "MUSTIG_LIB", qui décrit les procédures utilisées. On voit des déclarations de signaux, dont deux sont initialisés. L'une des valeurs initiales de ces deux signaux est la valeur du coefficient du filtre. L'autre, non visible sur le graphe MUSTIG ci-dessus, est la valeur initiale du retard, qui se trouve à l'intérieur de la macro "Retard". Ensuite, chaque opérateur MUSTIG correspond à un appel à la procédure VHDL équivalente. Le retard correspond  à l'appel de la procédure "DELAY". Mais il faut noter que l'on trouvera des appels  à  la procédure "DELAY" pour des graphes MUSTIG qui ne contiennent pas de macro retard. Il est ainsi possible de redessiner le graphe de la macro "Filtre RII" comme ci-dessous, dans une forme qui est équivalente à la précédente pour le compilateur MUSTIG comme pour le transcodeur VHDL (Pour en avoir l'explication, voir la notice générale MUSTIG). On pourrait vérifier que le code VHDL produit est identique à quelques permutations de lignes et de noms de signaux.

 

Notons que la valeur du coefficient (0.7) est fournie par un module valeur. Elle pourrait être fournie par un graphe MUSTIG, comme ci-dessous : le code VHDL serait inchangé.

 

Coefficient externe

Dans les exemples précédents, le coefficient est interne à la macro. On peut préférer le rendre accessible par l'extérieur. Il suffit d'ajouter une borne à la macro.

Cela ne change rien à la simulation MUSTIG. Par contre, les fichiers VHDL vont être modifiés.

Nous ne présentons que les exemples ce code produit avec l'option "Const. as Generic" cochée, ce qui est l'option par défaut.

entity FiltreRII1a is

library IEEE;

use IEEE.STD_LOGIC_1164.all;

generic (Coefficient : REAL);

port (CLK : in BIT;

      Entree : in REAL;

      Sortie : out REAL);

end;

 

library IEEE;

use IEEE.STD_LOGIC_1164.all;

library MUSTIG_LIB;

use MUSTIG_LIB.SYNTHESIS_PKG.all;

use MUSTIG_LIB.PROCEDURES_PKG.all;

architecture MUSTIG of FiltreRII1a is

      signal Si1 : REAL :=  0.00000000e+00;

      signal Si2 : REAL;

      signal Reboucle_3 : REAL;

      signal Somme_4 : REAL;

      signal Si5 : REAL;

begin

      M1 : MULT(IN2 => Coefficient,IN1 => Si2,OUTS => Reboucle_3);

      A2 : ADD(IN2 => Reboucle_3,IN1 => Entree,OUTS => Somme_4);

      Sortie <= Somme_4;

      F3 : DELAY(CLK,Somme_4,Si2,Si1);

end MUSTIG;

On voit que la borne supplémentaire, qui ne véhicule qu'une constante (c'est à dire un signal qui ne dépend pas de la variable "t") est traduite pas un paramètre VHDL de type "generic". Sa valeur n'apparaît donc plus dans la description du filtre. Elle se trouvera dans le fichier "test.vhd": le paramètre "generic" y est déclaré avec sa valeur numérique.

 

entity TEST is end TEST;

library IEEE;

use IEEE.STD_LOGIC_1164.all;

library MUSTIG_LIB;

use MUSTIG_LIB.IO_PKG.all;

use STD.TEXTIO.all;

architecture BENCH of TEST is

      constant PERIOD : TIME := 1.000000e+00 NS;

      component FiltreRII1a

      generic (Coefficient : REAL :=  6.99999988e-01);

      port (CLK : in BIT;

            Entree : in REAL;

            Sortie : out REAL);

      end component;

      for TST : FiltreRII1a use entity WORK.FiltreRII1a(MUSTIG);

      signal CLK : BIT;

      signal Entree : REAL;

      signal Sortie : REAL;

      file F_ENTREE : TEXT is in "filtrerii1a_entree.dat";

      file F_SORTIE : TEXT is out "filtrerii1a_sortie.dat";

begin

      CLK_GENERATOR : CLK <= not CLK after PERIOD/2;

      READ (F_ENTREE,CLK,Entree);

      TST : FiltreRII1a port map (CLK,Entree,Sortie);

      WRITE (F_SORTIE,CLK,Sortie);

end;

 

 

Filtre RIF (flottant)

Cette série d'exemples comporte une répétition de motifs faite par un "paquet" MUSTIG". On voit ainsi la génération de signaux indexés.

 

Coefficient interne

La vue externe du filtre est identique à celle du premier exemple "filtreRII1" ci-dessus.

Fichier filtrerif.vhd :

entity FiltreRIF is

library IEEE;

use IEEE.STD_LOGIC_1164.all;

port (CLK : in BIT;

      Entree : in REAL;

      Sortie : out REAL);

end;

La description du filtre est celle d'un filtre à réponse impulsionnelle finie de structure transversale directe. On utilise la syntaxe graphique MUSTIG de "paquet" pour ne dessiner qu'un motif de la structure répétitive de son diagramme de flux.

Sur l'entrée supérieure de l'opérateur "VHDL_MULT" arrive un ensemble de coefficients, un pour chaque cellule du filtre, considéré par MUSTIG comme une fonction de la variable "r". On pourra voir que ces coefficients sont le résultat d'un graphe MUSTIG qui en fait le calcul.

 

En observant le contenu du fichier "filtrerif_mustig.vhd", on voit que tout se passe comme si on avait dessiné toutes les cellules du filtre (ici cinq). Pour distinguer les signaux et les opérateurs d'une cellule à l'autre, les noms sont indexés. Par exemples, les signaux Si3_0, Si3_1, Si3_2, Si3_3, Si3_4, sont initialisés avec les valeurs des coefficients, et sont respectivement appliqués au multiplieurs M1_0, M1_1 , M1_2, M1_3, M1_4. Notons que le calcul des coefficients en MUSTIG n'est pas traduit en VHDL, seul le résultat apparaît.

library IEEE;

use IEEE.STD_LOGIC_1164.all;

library MUSTIG_LIB;

use MUSTIG_LIB.SYNTHESIS_PKG.all;

use MUSTIG_LIB.PROCEDURES_PKG.all;

architecture MUSTIG of FiltreRIF is

      signal Si1 : REAL :=  0.00000000e+00;

      signal Si2_0 : REAL;

      signal Si2_1 : REAL;

      signal Si2_2 : REAL;

      signal Si2_3 : REAL;

      signal Si2_4 : REAL;

      signal Si3_0 : REAL := -7.84550607e-02;

      signal Si3_1 : REAL :=  3.07805896e-01;

      signal Si3_2 : REAL :=  5.82031250e-01;

      signal Si3_3 : REAL :=  3.07805896e-01;

      signal Si3_4 : REAL := -7.84550682e-02;

      signal Si4 : REAL :=  0.00000000e+00;

      signal Si5_0 : REAL;

      signal Si5_1 : REAL;

      signal Si5_2 : REAL;

      signal Si5_3 : REAL;

      signal Si5_4 : REAL;

      signal Si6_0 : REAL;

      signal Si6_1 : REAL;

      signal Si6_2 : REAL;

      signal Si6_3 : REAL;

      signal Si6_4 : REAL;

      signal Si7_0 : REAL;

      signal Si7_1 : REAL;

      signal Si7_2 : REAL;

      signal Si7_3 : REAL;

      signal Si7_4 : REAL;

      signal Si8_0 : REAL;

      signal Si8_1 : REAL;

      signal Si8_2 : REAL;

      signal Si8_3 : REAL;

      signal Si8_4 : REAL;

      signal Si9 : REAL;

      signal Sortie_10 : REAL;

      signal Si11 : REAL;

begin

      M1_0 : MULT(IN2 => Si3_0,IN1 => Si5_0,OUTS => Si7_0);

      M1_1 : MULT(IN2 => Si3_1,IN1 => Si5_1,OUTS => Si7_1);

      M1_2 : MULT(IN2 => Si3_2,IN1 => Si5_2,OUTS => Si7_2);

      M1_3 : MULT(IN2 => Si3_3,IN1 => Si5_3,OUTS => Si7_3);

      M1_4 : MULT(IN2 => Si3_4,IN1 => Si5_4,OUTS => Si7_4);

      A2_0 : ADD(IN2 => Si7_0,IN1 => Si6_0,OUTS => Si8_0);

      A2_1 : ADD(IN2 => Si7_1,IN1 => Si6_1,OUTS => Si8_1);

      A2_2 : ADD(IN2 => Si7_2,IN1 => Si6_2,OUTS => Si8_2);

      A2_3 : ADD(IN2 => Si7_3,IN1 => Si6_3,OUTS => Si8_3);

      A2_4 : ADD(IN2 => Si7_4,IN1 => Si6_4,OUTS => Si8_4);

      Si5_0 <= Entree;

      Si5_1<=Si2_0;

      Si5_2<=Si2_1;

      Si5_3<=Si2_2;

      Si5_4<=Si2_3;

      Si6_0 <= Si4;

      Si6_1<=Si8_0;

      Si6_2<=Si8_1;

      Si6_3<=Si8_2;

      Si6_4<=Si8_3;

      Si9<=Si2_4;

      Sortie_10<=Si8_4;

      Sortie <= Sortie_10;

      F3_0 : DELAY(CLK,Si5_0,Si2_0,Si1);

      F3_1 : DELAY(CLK,Si5_1,Si2_1,Si1);

      F3_2 : DELAY(CLK,Si5_2,Si2_2,Si1);

      F3_3 : DELAY(CLK,Si5_3,Si2_3,Si1);

      F3_4 : DELAY(CLK,Si5_4,Si2_4,Si1);

end MUSTIG;

 

 

Coefficient externe

De la même façon que dans l'exemple de filtre récursif, on peut mettre les coefficients à l'extérieur de la macro. Ils apparaissent alors en paramètres génériques.

 

entity FiltreRIFa is

library IEEE;

use IEEE.STD_LOGIC_1164.all;

generic (Coefs_0 : REAL;

      Coefs_1 : REAL;

      Coefs_2 : REAL;

      Coefs_3 : REAL;

      Coefs_4 : REAL);

port (CLK : in BIT;

      Entree : in REAL;

      Sortie : out REAL);

end;

 

library IEEE;

use IEEE.STD_LOGIC_1164.all;

library MUSTIG_LIB;

use MUSTIG_LIB.SYNTHESIS_PKG.all;

use MUSTIG_LIB.PROCEDURES_PKG.all;

architecture MUSTIG of FiltreRIFa is

      signal Si1 : REAL :=  0.00000000e+00;

      signal Si2_0 : REAL;

      signal Si2_1 : REAL;

      signal Si2_2 : REAL;

      signal Si2_3 : REAL;

      signal Si2_4 : REAL;

      signal Si3 : REAL :=  0.00000000e+00;

      signal Si4_0 : REAL;

      signal Si4_1 : REAL;

      signal Si4_2 : REAL;

      signal Si4_3 : REAL;

      signal Si4_4 : REAL;

      signal Si5_0 : REAL;

      signal Si5_1 : REAL;

      signal Si5_2 : REAL;

      signal Si5_3 : REAL;

      signal Si5_4 : REAL;

      signal Si6_0 : REAL;

      signal Si6_1 : REAL;

      signal Si6_2 : REAL;

      signal Si6_3 : REAL;

      signal Si6_4 : REAL;

      signal Si7_0 : REAL;

      signal Si7_1 : REAL;

      signal Si7_2 : REAL;

      signal Si7_3 : REAL;

      signal Si7_4 : REAL;

      signal Si8 : REAL;

      signal Sortie_9 : REAL;

      signal Si10 : REAL;

begin

      M1_0 : MULT(IN2 => Coefs_0,IN1 => Si4_0,OUTS => Si6_0);

      M1_1 : MULT(IN2 => Coefs_1,IN1 => Si4_1,OUTS => Si6_1);

      M1_2 : MULT(IN2 => Coefs_2,IN1 => Si4_2,OUTS => Si6_2);

      M1_3 : MULT(IN2 => Coefs_3,IN1 => Si4_3,OUTS => Si6_3);

      M1_4 : MULT(IN2 => Coefs_4,IN1 => Si4_4,OUTS => Si6_4);

      A2_0 : ADD(IN2 => Si6_0,IN1 => Si5_0,OUTS => Si7_0);

      A2_1 : ADD(IN2 => Si6_1,IN1 => Si5_1,OUTS => Si7_1);

      A2_2 : ADD(IN2 => Si6_2,IN1 => Si5_2,OUTS => Si7_2);

      A2_3 : ADD(IN2 => Si6_3,IN1 => Si5_3,OUTS => Si7_3);

      A2_4 : ADD(IN2 => Si6_4,IN1 => Si5_4,OUTS => Si7_4);

      Si4_0 <= Entree;

      Si4_1<=Si2_0;

      Si4_2<=Si2_1;

      Si4_3<=Si2_2;

      Si4_4<=Si2_3;

      Si5_0 <= Si3;

      Si5_1<=Si7_0;

      Si5_2<=Si7_1;

      Si5_3<=Si7_2;

      Si5_4<=Si7_3;

      Si8<=Si2_4;

      Sortie_9<=Si7_4;

      Sortie <= Sortie_9;

      F3_0 : DELAY(CLK,Si4_0,Si2_0,Si1);

      F3_1 : DELAY(CLK,Si4_1,Si2_1,Si1);

      F3_2 : DELAY(CLK,Si4_2,Si2_2,Si1);

      F3_3 : DELAY(CLK,Si4_3,Si2_3,Si1);

      F3_4 : DELAY(CLK,Si4_4,Si2_4,Si1);

end MUSTIG;

 

 

Filtre récursif du premier ordre en arithmétique entière

L'option "arithmétique à précision finie" autorise la simulation d'un filtre en maîtrisant le nombre de bits des mots en chaque point. On se référera à la notice spéciale concernant cette option et à la description des exemples inclus.

Partons du premier filtre récursif de ces exemples. Son environnement de test simplifié est le suivant :

La macro "Fixv" convertit le signal d'entrée sur 12 bits dont 11 fractionnaires.

 

La description interne du filtre est :

Pour pouvoir effectuer un transcodage VHDL de ce filtre, il faut mettre des étiquettes aux bornes et remplacer le module "+" et la macro "ivCoef" par des macros de type VHDL. La macro "Fixv" d'entrée peut subsister, car le module "Fix_iv" qu'elle contient est traduit automatiquement par le transcodeur VHDL. L'autre macro "Fixv" concerne une constante et ne sera donc pas transcodée.

Pour transformer la macro "ivCoef" en la macro "VHDL_ivCoef", il faut légèrement modifier l'intérieur. Il faut principalement ajouter des étiquettes sur les bornes.

Les noms de ces étiquettes correspondent à ceux de sa déclaration dans le  fichier "procedure_pkg_.vhd" :    

procedure ivCOEF (signal IN1 : in STD_ULOGIC_VECTOR;

                  signal IN2 : in STD_ULOGIC_VECTOR;

                  signal OUTS : out STD_ULOGIC_VECTOR);

Il faut également ajouter un module ineffectif "=" sur la borne d'entrée dont le signal est distribué à deux endroits, en raison d'une limitation actuelle du transcodeur VHDL (Sinon, un message le demande :  "Il faut isoler cette borne...").

Voici la description VHDL de l'intérieur du filtre.

library IEEE;

use IEEE.STD_LOGIC_1164.all;

library MUSTIG_LIB;

use MUSTIG_LIB.SYNTHESIS_PKG.all;

use MUSTIG_LIB.PROCEDURES_PKG.all;

architecture MUSTIG of iv_Filtre1 is

      signal Si1 : REAL :=  0.00000000e+00;

      signal Si2 : STD_ULOGIC_VECTOR(89 to 105);

      signal Si3 : STD_ULOGIC_VECTOR(91 to 100) := '0111100110'   --   9.49218750e-01;

      signal Si4 : STD_ULOGIC_VECTOR(89 to 105);

      signal Si5 : STD_ULOGIC_VECTOR(89 to 105);

      signal Si6 : STD_ULOGIC_VECTOR(89 to 105);

      signal Si7 : STD_ULOGIC_VECTOR(89 to 105);

begin

      I1 : IVCOEF(IN2 => Si3,IN1 => Si2,OUTS => Si4);

      X2 : FIXV(INS => Input,OUTS => Si5);

      A4 : ADD(IN2 => Si4,IN1 => Si5,OUTS => Si6);

      Output <= Si6;

      F5 : DELAY(CLK,Si6,Si2,Si1);

end MUSTIG;

On peut voir que le type MUSTIG "entier à précision variable" est transformé en un vecteur de bits, dimensionné en fonction du nombre de bits du graphe MUSTIG. On peut également voir que l'initialisation en est faite sous forme binaire (suite de 0 et de 1). Notons que la position de la virgule, qui est une commodité offerte par la simulation MUSTIG, a ici disparu. Par contre, la valeur correspondante est rappelée en commentaire.

Notons que l'on aurait pu laisser la macro iv_Coef comme une macro MUSTIG ordinaire, en remplaçant à l'intérieur le module "x" par une macro "VDHL_MULT".  On aurait alors obtenu un code VHDL avec le multiplieur complet et l'appel à FIXV qui correspond à une réduction du nombre de bits. Cela est probablement moins réaliste, car le multiplieur qui ne sort que les bits de poids forts peut être plus simple que le multiplieur complet.

Le fichier de test est très peu différent du fichier de test en réels. Observons par contre le fichier de donnée.

....

.....

0.11100110011  8.99902344e-01

0.11100110011  8.99902344e-01

0.11100110011  8.99902344e-01

0.00000000000  0.00000000e+00

0.00000000000  0.00000000e+00

....

.....

 

Les valeurs y sont représentées d'une part en binaire, avec un point décimal. D'autre part en flottant. Cette double représentation permet d'avoir à la fois une représentation toujours exacte au bit près et une représentation facile à lire.

 

 

Filtre récursif du premier ordre en arithmétique entière (autre forme)

Étudions la forme suivante de réalisation d'un filtre passe-bas du premier ordre. Elle est plus économique que la forme précédente, puisque la multiplication nécessite moins de précision.

On y voit la présence de l'opérateur "shift", dont la fonction est une division par un nombre égal à une puissance de 2. Il est suivi d'une macro "FIXV" qui réduit le nombre de bits. Pour la réalisation, l'ensemble de ces deux opérations correspondra seulement à des connections. On préférera donc peut-être mettre un seul opérateur VHDL pour "shift" et "Fixv". C'est un opérateur qui ne garde que les poids forts d'un mot. La macro VHDL_DIV_SHIFT réalise cette fonction. En MUSTIG, elle n'a comme paramètre que le nombre de bits de décalage, le nombre de bits résultant est calculé.

 En VHDL, c'est ce nombre de bits de sortie qui sert de paramètre : les poids forts de la sortie sont les poids forts de l'entrée.

 

library IEEE;

use IEEE.STD_LOGIC_1164.all;

library MUSTIG_LIB;

use MUSTIG_LIB.SYNTHESIS_PKG.all;

use MUSTIG_LIB.PROCEDURES_PKG.all;

architecture MUSTIG of iv_Filtre1_c is

      signal Si1 : REAL :=  0.00000000e+00;

      signal Si2 : STD_ULOGIC_VECTOR(89 to 105);

      signal Si3 : STD_ULOGIC_VECTOR(95 to 100) := '011001'   --   7.81250000e-01;

      signal Si4 : STD_ULOGIC_VECTOR(89 to 101);

      signal Si5 : STD_ULOGIC_VECTOR(89 to 101);

      signal Si6 : STD_ULOGIC_VECTOR(89 to 101);

      signal Si7 : STD_ULOGIC_VECTOR(89 to 101);

      signal Si8 : STD_ULOGIC_VECTOR(89 to 105);

      signal Si9 : STD_ULOGIC_VECTOR(89 to 105);

      signal Si10 : STD_ULOGIC_VECTOR(89 to 105);

begin

      D1 : DIVSHIFT(OUTS => Si4,INS => Si2);

      I2 : IVCOEF(IN2 => Si3,IN1 => Si4,OUTS => Si5);

      X3 : FIXV(INS => Input,OUTS => Si6);

      S5 : SUB(IN2 => Si5,IN1 => Si6,OUTS => Si7);

      X6 : FIXV(INS => Si7,OUTS => Si8);

      A8 : ADD(IN2 => Si2,IN1 => Si8,OUTS => Si9);

      Output <= Si9;

      F9 : DELAY(CLK,Si9,Si2,Si1);

end MUSTIG;