[AUDIO_VIDE] Bonjour. Nous allons continuer le cours sur les enseignes et afficheurs à LED. Aujourd'hui nous allons aborder les instructions concurrentes en VHDL. Dans cette leçon, nous allons voir les instructions concurrentes à travers l'affectation simple, l'affectation sélective et l'affectation conditionnelle. Nous allons aussi voir les components, les composants, et nous allons terminer cette leçon par la génération conditionnelle. Le VHDL distingue deux domaines d'instructions. Les instructions concurrentes, les instructions séquentielles. Les instructions concurrentes permettent de modéliser des comportements dirigés par des événements asynchrones et qui s'exécutent en parallèle. Les instructions concurrentes sont utilisées dans l'architecture et peuvent être écrites dans un ordre quelconque. Les instructions concurrentes utilisent l'affectation concurrente de signaux. Nous avons l'affectation simple, l'affectation conditionnelle et l'affectation sélective. Les instructions concurrentes en VHDL permettent de décomposer un problème en fonctions simples qui peuvent s'exécuter de manière concurrente, c'est-à -dire en ensemble de composants ou d'algorithmes qui peuvent travailler ensemble et qui pourraient même agir les uns sur les autres. Chaque instruction effectue donc un traitement en parallèle avec les autres, et donc l'ordre d'écriture n'a aucune importance. Pour l'affectation simple, il s'agit tout simplement d'une connexion de deux signaux. Il s'agira d'affecter, par exemple pour la syntaxe, le signal, 1, au signal. Alors si nous prenons l'exemple de cette fonction simple, au niveau de l'entité, cette fonction a deux entrées, e1 et e2, et deux sorties, s1 et s2. Au niveau des ports, nous avons déclaré les quatre signaux. Au niveau de la sortie s1, nous avons un, ET logique, entre, e1 et e2, et au niveau de s2 nous avons un, OU logique, entre, e1 et e2. Il est simple de comprendre qu'on aurait pu écrire cette affectation avant la première. Et nous avons ici le circuit qui est réalisé à partir de ce programme. L'affectation conditionnelle, WHEN / ELSE. C'est une instruction qui a une seule cible. Ici, la cible c'est signal. Et nous avons plusieurs expressions, c'est-à -dire signal peut prendre la valeur, signal 1, quand l'expression 1 est vraie, signal peut prendre la valeur, signal 2, quand l'expression2 est vraie sinon signal va prendre la valeur, signal 3. Nous allons appliquer l'affectation conditionnelle pour réaliser notre multiplexeur, mux2, deux entrées, une sortie. Au niveau de l'entité, nous avons nos deux entrées, e1 et e2, notre sélecteur, sel, qui est aussi une entrée, et la sortie, s. Et au niveau de l'architecture, e1 est affecté à la sortie quand le sélecteur est égal à zéro, sinon, e2 est affecté à la sortie. Donc ici, nous avons une seule cible qui est, s, et l'expression ici, 1 correspond à , sel égale zéro, et donc, e1 est affecté às si sel égale zéro, et, e2 est affecté às si sel est différent de zéro ; c'est-à -dire sel égale 1. Et la structure du composant qui est réalisé est présentée ici. La syntaxe de l'affectation sélective, WITH......SELECT, permet d'avoir, ici, au niveau de notre expression testée, qui peut valoir, valeur 1, valeur 2 ,ou une autre valeur, signal 1 va être affecté à signal quand expression est égale à valeur 1. Signal va prendre la valeur, signal 2, lorsque l'expression est égale à valeur 2, et signal va prendre la valeur, signal 3, dans tous les autres cas. C'est-à -dire tous les autres cas où on a l'expression qui est différente de valeur 1 et valeur 2, signal va prendre signal 3. Nous allons utiliser cette affectation sélective pour synthétiser un décodeur sept segments. Voici notre afficheur sept segments. Nous avons les segments de A à G. Et le principe du décodage consiste à prendre les valeurs, on va prendre les valeurs décimales, qui peuvent être représentées ici par, data, sur quatre bits. Pour écrire les valeurs de 0 à 9, on a besoin de quatre bits. Et donc nous avons aussi les sept sorties qui est représenté ici par ce vecteur sept segments, qui est une sortie, zéro to 6. Alors les bits sont disposés du poids faible, c'est-à -dire le A jusqu'au poids fort, le G. Donc le A ici prend la première place et le G prend la dernière place. C'est très important. Donc l'architecture de notre décodeur, nous avons utilisé donc l'affectation sélective, WITH.....SELECT. Alors on va chercher l'expression, data, qui peut valoir zéro, 1, jusqu'à 9. Alors, retenez tout simplement que le, x, ici, devant ces valeurs, symbolise que les valeurs sont inscrites en hexadécimal. Le principe de notre décodage est simple. Donc il suffit d'affecter au niveau de nos sept segments les valeurs qu'il faut pour afficher le chiffre souhaité. Alors les chiffres sont là , de zéro jusqu'à 9. Alors il faut juste préciser que l'afficheur est à anode commune, c'est-à -dire pour afficher un segment, il faut envoyer un zéro. Donc ici pour afficher le zéro, on doit allumer les six premiers segments et on doit éteindre le dernier segment qui correspond au segment G. Pour afficher un 1, on doit allumer le deuxième et le troisième segment, c'est-à -dire B et C et doit éteindre tout le reste. Et vous pouvez comprendre le reste. IL faut juste souligner la dernière ligne, on doit éteindre tous les LED lorsqu'on a, data, qui vaut autre chose que zéro à 9, c'est-à -dire, when others, c'est tous les autres cas en dehors des cas qui sont listés ici. Les composants. Le mot clé COMPONENT permet de définir des modèles ou prototypes de composants en dehors de l'architecture, et donc d'offrir plus de souplesse dans le cas où plusieurs architectures de composants sont possibles. Il s'agit donc de définir un modèle, puis après de l'instancier pour avoir des composants. Donc ici nous avons le nom de l'instance pour l'instanciation, donc chaque instance a un nom, deux points, le nom du composant, suivi de, port map, ensuite de la liste des signaux. Alors la liste des connexions, c'est les variables qu'on va donner, les signaux qu'on va donner au niveau de l'instanciation du composant. Nous allons utiliser le COMPONENT pour créer un composant nous permettant de décoder, cette fois-ci pour pouvoir afficher quatre chiffres décimaux. Donc nous pourrons éventuellement compter de zéro jusqu'à 9999. Alors l'architecture de notre décodeur est ici. Nous avons au niveau des ports, SW, qui est déclaré comme une variable logique à 16 bits. Nous avons déclaré ici une sortie, OUT, qui est aussi une variable logique à 16 sorties, à 16 bits. Nous avons déclaré quatre afficheurs, ici. Chaque afficheur a sept segments. Au niveau de l'architecture de notre décodeur sept segments, nous avons créé un composant, le mot clé COMPONENT, suivi du nom du composant que nous avons déjà vu tout à l'heure, ensuite nous allons avoir donc nos quatre entrées du décodeur et nos sept sorties. Donc le principe est simple. Les entrées, ici la valeur qui est mise à l'entrée, ici, sera décodée, ici, au niveau de sortie pour afficher le bon chiffre. Alors au niveau de notre architecture, nous avons affecté tout simplement les entrées au niveau des sorties. Ça c'est pour des LED éventuellement, pour une histoire d'affichage. Alors les instances sont créées ici. Nous avons pour l'instance qui affiche le chiffre zéro, donc le nom du composant ici, PORT MAP, ensuite suivi des signaux. Alors l'idée de notre décodeur est d'afficher au niveau de l'afficheur numéro zéro, le digit zéro, les quatre premiers bits de notre vecteur à 16 bits, d'afficher au niveau de digit 1 les quatre bits suivants de 4 à 7, et d'afficher au niveau de digit 2 les quatre bits suivants, 8 à 11, et d'afficher au niveau de digit 3 Les quatre bits suivants de 12 à 15. Ici, nous avons les quatre afficheurs, sept segments. Donc, la valeur qui est envoyée ici au niveau de ces quatre bits sera affichée au niveau de HEX0. La valeur qui est envoyée au niveau de ces quatre bits suivants sera affichée au niveau de HEX1. La valeur qui est renvoyée au niveau de ces quatre bits suivants sera affichée en HEX2, ainsi de suite. La génération conditionnelle utilise l'instruction GENERATE qui permet la description de comportements ou de structures régulières. Elle permet de multiplier des instructions soit en nombre de fois fixe. À ce moment-là , elle utilise l'instruction for. Soit de manière conditionnelle. À ce moment-là , elle utilise l'instruction if. Au niveau de la syntaxe, nous avons un label suivi de deux points, ensuite if suivi d'une condition, generate et end generate, et entre les deux, une suite d'instructions concurrentes peut s'exécuter tant que la condition est vraie. Elle peut s'utiliser aussi avec l'instruction for pour une suite d'instructions itératives concurrentes. À ce moment-là , label suivi de deux points, for pour une variable variant de 0 jusqu'à x generate, et une suite d'instructions qui s'exécutent x + 1 fois. Nous allons utiliser la génération conditionnelle pour synthétiser un additionneur quatre bits à partir d'un additionneur un bit. Voici les équations de notre additionneur un bit. Nous avons ici s0, la sortie de l'additionneur un bit, à partir des entrées a0 et b0, et de la retenue ri. Ici, c'est la retenue r0, et donc nous avons les deux équations pour la sortie et pour la retenue. Au niveau de l'architecture de notre additionneur, nous avons commencé par l'additionneur un bit d'abord. L'entrée ici, nous avons la retenue initiale, les deux entrées qui sont des bits a et b, la sortie de notre additionneur un bit, et la retenue de notre additionneur un bit. Au niveau de l'architecture, nous avons tout simplement implémenté les deux équations que nous venons de vous présenter. Pour utiliser maintenant notre additionneur un bit pour réaliser l'additionneur quatre bits, au niveau de l'architecture de notre additionneur quatre bits, nous avons la retenue initiale, les deux valeurs qui sont représentées cette fois-ci sur quatre bits et notre sortie qui est éventuellement représentée sur quatre bits et notre retenue finale. Au niveau de l'architecture de notre additionneur quatre bits, nous avons commencé par créer un composant additionneur un bit. Donc, c'est le même composant que nous avons réalisé ici. Nous avons ici déclaré un signal C, au niveau de l'architecture, qui permet de représenter les retenues internes, c'est-à -dire les retenues qui ne sortent pas du composant. Donc, on a initialisé ici le premier bit de C à la retenue initiale. Ensuite, nous allons générer les quatre additionneurs. Ici, avec le label A, que nous avons fermé ici, pour A, i allant de 0 jusqu'à 3, donc quatre itérations, nous allons créer notre premier additionneur un bit. On va lui donner la retenue initiale. La première valeur de A, A(0), B(0), et la sortie, c'est-à -dire le résultat de ce premier additionneur interne est mis dans s(0), et la retenue interne est remise dans C(0). Ensuite, on ferme ici la première génération. Donc, on va partir maintenant pour i > 0, c'est-à -dire on commence par 1, 2, 3. La retenue précédente est injectée au niveau de la retenue suivante. Le A(1), B(1), résultat sur s(1), retenue sur C(1), et on recommence. Donc, on le fait trois fois. À la fin, on ferme ici le GENERATE pour le MSB, et après, la retenue, les signaux sont mis à jour ici à la fin. Donc, la retenue qui se trouve sur ces trois est mise au niveau de la retenue finale. Nous venons de voir des instructions concurrentes en VHDL, à travers l'affectation concurrente des signaux. Nous avons vu l'affectation simple, l'affectation conditionnelle, l'affectation sélective. Nous avons également vu les composants, avec le mot-clé Component, et nous avons terminé cette leçon par la génération conditionnelle. La prochaine étape sera d'aborder les instructions séquentielles.