Leçons de niveau 15

Very High Speed Integrated Circuit Hardware Description Language/Travail pratique/TPs de préparation

Une page de Wikiversité.
Aller à : navigation, rechercher
Début de la boite de navigation du travail pratique
TPs de préparation
Image logo représentative de la faculté
T.P. no 1
Leçon : Very High Speed Integrated Circuit Hardware Description Language

Ce TP est de niveau 15.

Précédent : Sommaire
Suivant : TP 2
Icon falscher Titel.svg
En raison de limitations techniques, la typographie souhaitable du titre, « Travail pratique : TPs de préparation
Very High Speed Integrated Circuit Hardware Description Language/Travail pratique/TPs de préparation
 », n'a pu être restituée correctement ci-dessus.

Nous allons regrouper dans ce chapitre un ensemble de TPs qui sont réalisées en niveau 14 (L1). Ils ne correspondent pas au niveau de ce livre, mais sont livrés ici pour permettre justement une préparation au contenu de ce livre. En clair il s'agit plutôt de TPs de préparation ou même de révision.

Sommaire

Utilisation Basys2 avec ADEPT sous Linux[modifier | modifier le wikicode]

En principe, avec les versions modernes de l'ISE, c'est IMPACT qui se chargera de télécharger dans le FPGA. Si vous rencontrez des problèmes de téléchargement, ADEPT peut être utilisé en ligne de commande.

On utilisera la carte Basys 2 avec un SPARTAN 3E 250 (xc3s250e) dans un boîtier CP132.

Commandes ADEPT et ISE
Detection
djtgcfg enum
donne Basys2 come username
Téléchargement
djtgcfg prog -d Basys2 --index 0 --file toto.bit <<<y
Lancement ISE
/opt/Xilinx/14.5/ISE_DS/ISE/bin/lin/ise &

TP1 - Des Tables de vérité et VHDL aux simplifications (3 heures)[modifier | modifier le wikicode]

L'objectif de ce TP est de montrer qu'avec un FPGA la connaissance d'une table de vérité suffit pour réaliser un programme VHDL (sans les simplifier). Cependant, pour vous faire travailler les tableaux de Karnaugh, on vous demandera parfois de trouver les équations et de les implanter. A la fin de ce TP, vous serez capable

  • d'établir une table de vérité
    • d'en déduire immédiatement le programme VHDL correspondant
    • ou de la transformer à l'aide d'un tableau de Karnaugh en une équation simplifiée et de l'implanter en VHDL

Tous ces allers et retours entre toutes ces formes (Table de vérité, Tableau de Karnaugh, équations) sont la base de l'apprentissage.

Un exemple simple pour comprendre l'IDE Xilinx[modifier | modifier le wikicode]

Vous allez réaliser un simple OU en suivant un exemple complet réalisé par votre enseignant. L'objectif est d'apprendre :

  • à réaliser un fichier VHDL, le sauver et l'ajouter au projet
  • à réaliser un fichier de contrainte pour choisir les entrées et sorties, et l'ajouter au projet
  • à compiler
  • à charger le fichier dans votre FPGA avec IMPACT ou ADEPT

Voici les fichiers VHDL utilisés :

  • à partir d'une table de vérité
library IEEE;
use IEEE.STD_LOGIC_1164.all;
ENTITY ou IS
  PORT(e0,e1 : IN std_logic;
 	s : OUT std_logic);
END ou;
ARCHITECTURE arch_ou OF ou IS
  SIGNAL entrees : std_logic_vector(1 downto 0);
 BEGIN
   entrees <= e1 & e0;
   WITH entrees SELECT
     s <= '1' WHEN "01" | "10" | "11",
          '0' WHEN OTHERS;
END arch_ou;
  • à partir d'une équation
library IEEE;
use IEEE.STD_LOGIC_1164.all;
ENTITY ou IS
  PORT(e0,e1 : IN std_logic;
 	s : OUT std_logic);
END ou;
ARCHITECTURE arch_ou OF ou IS
 BEGIN
   s <= e0 OR e1;
END arch_ou;

Modifier cet exemple pour ajouter une sortie qui réalise un ET.

Fichier ucf utile pour Basys 2[modifier | modifier le wikicode]

Pour éviter de chercher nous donnons quelques contenus du fichier ucf :

# Pin assignment for SWs 
NET "sw7" LOC = "N3";  # Bank = 2, Signal name = SW7 
NET "sw6" LOC = "E2";  # Bank = 3, Signal name = SW6 
NET "sw5" LOC = "F3";  # Bank = 3, Signal name = SW5 
NET "sw4" LOC = "G3";  # Bank = 3, Signal name = SW4 
NET "sw3" LOC = "B4";  # Bank = 3, Signal name = SW3 
NET "sw2" LOC = "K3";  # Bank = 3, Signal name = SW2 
NET "sw1" LOC = "L3";  # Bank = 3, Signal name = SW1 
NET "sw0" LOC = "P11";  # Bank = 2, Signal name = SW0
# Pin assignment for LEDs 
NET "Led7" LOC = "G1" ; # Bank = 3, Signal name = LD7 
NET "Led6" LOC = "P4" ; # Bank = 2, Signal name = LD6 
NET "Led5" LOC = "N4" ;  # Bank = 2, Signal name = LD5 
NET "Led4" LOC = "N5" ;  # Bank = 2, Signal name = LD4 
NET "Led3" LOC = "P6" ; # Bank = 2, Signal name = LD3
NET "Led2" LOC = "P7" ; # Bank = 3, Signal name = LD2 
NET "Led1" LOC = "M11" ; # Bank = 2, Signal name = LD1 
NET "Led0" LOC = "M5" ;  # Bank = 2, Signal name = LD0

Exercice 1 : Analyse d'un schéma simple puis synthèse équivalente[modifier | modifier le wikicode]

Un schéma logique et son tableau de Karnaugh correspondant

On donne le schéma ci-contre.

1°) Plot the corresponding function in the truth table below and in the Karnaugh map. Find the simplified sum of product expression of s=f(e0,e1,e2).

Table de vérité
Entrées Sorties
e2 e1 e0 a b s
0 0 0 ? ? ?
0 0 1 ? ? ?
0 1 0 ? ? ?
0 1 1 ? ? ?
1 0 0 ? ? ?
1 0 1 ? ? ?
1 1 0 ? ? ?
1 1 1 ? ? ?

Remarque : a et b ne sont pas à proprement parler des sorties. Il s'agit de fils intermédiaires, mais il faut les calculer pour avoir s.

2°) Realize the corresponding simplified expression as a VHDL program with an equation.

3°) Realize the corresponding simplified expression as a VHDL program with a with select when.

Exercice 2 (Vote au directoire)[modifier | modifier le wikicode]

Le comité directeur d’une entreprise est constitué de quatre membres :

  • le directeur D,
  • ses trois adjoints A, B, C.

Lors des réunions, les décisions sont prises à la majorité.

Chaque personne dispose d’un interrupteur pour voter sur lequel elle appuie en cas d’accord avec le projet soumis au vote. En cas d'égalité du nombre de voix, celle du directeur compte double.

On vous demande de réaliser un dispositif logique permettant l’affichage du résultat du vote sur lampe V (pour nous ce sera une LED).

1°) Écrire une table de vérité pour la sortie V puis un tableau de Karnaugh

2°) Réaliser le programme VHDL pour la sortie V avec un with select when (autrement dit à partir de la table de vérité).

3°) Réaliser le programme VHDL pour la sortie V avec une équation (si possible simplifiée avec un tableau de Karnaugh).

Exercice 3 (Vote au directoire amélioré)[modifier | modifier le wikicode]

Une société est composée de 4 actionnaires ayant les nombres suivants d'actions A=60, B=100, C=160 et D=180.

Nous désirons construire une machine à voter automatiquement, tenant compte dans le résultat du poids en actions de chaque personne. La machine dispose de 4 boutons poussoirs A, B, C, D et le résultat sera un voyant V qui s'allumera si la majorité pondérée appuie sur les boutons.

1°) Écrire une table de vérité pour la sortie V. Réaliser le programme VHDL correspondant et vérifier que vous avez la bonne table de vérité.

2°) Réaliser le programme VHDL avec un with select when. Remarquez l'apparition d'un WARNING.

3°) Pour comprendre le WARNING de la question précédente, on vous demande de trouver l'équation simplifiée. En l'examinant vous comprendrez quel est le problème. Puis réaliser le programme VHDL avec une équation logique pour la sortie V en supprimant le WARNING.

TP2 - Des tables de vérités aux LUT4 (en VHDL)[modifier | modifier le wikicode]

Les LUT4 sont aux FPGA ce que les portes logiques sont aux schémas : des briques de base à assembler. Les portes logiques sont figées mais vous pouvez choisir celles qui vous intéressent. Pour les LUT4, ce sont des composants à 4 entrées qui sont universels : ils peuvent réaliser n'importe quelle fonction logique.

Des tables de vérité à l'hexadécimal (cours sur LUTs)[modifier | modifier le wikicode]

Une table de vérité de trois entrées peut être représentée par un nombre 8 bits que l'on convertit en hexadécimal. Soit donc la table de vérité suivante (trois entrées notées e0, e1 et e2, une sortie notée s) :

Table de vérité
Entrées Sorties bits
e2 e1 e0 s
0 0 0 0 b0
0 0 1 1 b1
0 1 0 1 b2
0 1 1 0 b3
1 0 0 1 b4
1 0 1 0 b5
1 1 0 1 b6
1 1 1 0 b7

Vous pouvez synthétiser la table de vérité à l'aide d'un seul nombre sur 8 bit (poids faible en haut) :

  • en binaire ce nombre vaut : 0b01010110
  • en hexadécimal ce nombre vaut : 0x56 (X"56" en VHDL)

La valeur hexadécimale 56 est la valeur qu'il vous faudra utiliser dans la partie INIT d'une (catégorie) LUT qu'il faudra câbler.



Utiliser des LUTs en VHDL[modifier | modifier le wikicode]

Un exemple est donné maintenant :

library IEEE; -- transodeur binaire -> 7 segments
use IEEE.STD_LOGIC_1164.ALL; 
library unisim; 
use unisim.vcomponents.all;
ENTITY transcodeur IS PORT(
  e : in STD_LOGIC_VECTOR(3 DOWNTO 0);   -- 4 entrées
  s : out STD_LOGIC_VECTOR(6 DOWNTO 0)); -- 7 sorties
END transcodeur;
ARCHITECTURE atranscodeur OF transcodeur IS BEGIN
 i1 : LUT4 
   generic map (INIT => X"EAAA") 
   port map( I0 => e(0), 
             I1 => e(1), 
             I2 => e(2), 
             I3 => e(3), 
              O => s(0) );
 .....

Cet exemple vous montre comment on câble une LUT4 en VHDL (port map) et comment on l'initialise (generic map). Le câblage de ce composant est correct mais pas son initialisation puisqu'on vous demande de la calculer plus loin.

Les deux lignes library ... et use ... sont à ajouter avant toute entité qui utilise une LUT en plus bien sûr de "library ieee;".

Multiplieur de deux nombres de 2 bits[modifier | modifier le wikicode]

Exercise 1 (English)[modifier | modifier le wikicode]

Design and build a combinational logic circuit with four inputs and four outputs that multiplies two 2-bits numbers, labeled X, and Y. The output is labeled Z. Use a truth table and find out the corresponding with select when.

 
library IEEE;
use IEEE.std_logic_1164.all;
entity multiplier is
    port (  X,Y: in STD_LOGIC_VECTOR (1 downto 0);	-- binary inputs
        Z : out STD_LOGIC_VECTOR (3 downto 0));	-- binary output
end multiplier;

1°) Réaliser ce circuit avec un WITH SELECT WHEN

2°) Réaliser ensuite ce circuit avec 4 LUT4

Transcodeur binaire 7 segments[modifier | modifier le wikicode]

Lire Afficheur 7 segments.

On va réaliser un transcodeur binaire décimal vers un afficheur 7 segments. L'objectif de ce TP est d'utiliser toutes les techniques classiques de synthèse combinatoire.

Présentation du sujet[modifier | modifier le wikicode]

Un schéma présente de manière symbolique ce que l'on cherche à faire.

Gestion d'un afficheur 7 segments par un FPGA

sel est choisi à 0 pour sélectionner l'afficheur de gauche. La valeur binaire (de 0 à F) choisie sur les interrupteurs est convertie pour être affichée comme ci-contre.

Affichage hexadécimal désiré : le passage d'un chiffre à un autre est réalisé par des interrupteurs

Exercice 2 : Transcodeur hexadécimal vers sept segments et « with select when »[modifier | modifier le wikicode]

1°) First complete the truth table below. Read the first line carefully before starting.

Table de vérité
Entrées Sorties
sw3 sw2 sw1 sw0 a b c d e f g
0 0 0 0 0 0 0 0 0 0 1
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1

2°) Realize this truth table as circuit in VHDL (style "with select when").

3°) Faire la même réalisation en utilisant des LUT4.

Il serait bon de mettre de côté un programme solution de la question 2° ou celle de l'équation 3°. Vous en aurez besoin plus tard.

Exercice 3 : Transcodeur pour dé[modifier | modifier le wikicode]

Un FPGA comme transcodeur pour un dé

1°) Réaliser le transcodeur ci-contre avec les LEDs présentes sur la carte FPGA en utilisant un with select when. Ce que vous avez à réaliser est donc un circuit qui comporte 3 interrupteurs en entrée et 7 leds en sortie (voir schéma ci-contre).

2°) Faire le même travail avec 7 LUT4.

3°) En gardant ce que vous avez fait en question 2°, on vous demande d'y ajouter un affichage sur les sept segments en utilisant le programme de la question 2° ou 3° de l'exercice précédent (que l'on vous avez demandé de mettre de côté).

Malheureusement les tests ne seront pas facilités puisque les leds utilisées sont alignées... mais l'esprit humain peut contourner ce genre de détail.

TP3 Arithmétique, comparateurs et multiplexeurs[modifier | modifier le wikicode]

L'arithmétique consiste à implanter des fonctions de base de l'arithmétique, c'est à dire addition, soustraction et multiplication. L'utilisation de l'arithmétique dans un FPGA doit suivre ses propres règles. Nous allons commencer par examiner l'addition, d'abord sans se préoccuper du fait que l'on utilise un FPGA, puis on cherchera à utiliser les composants Xilinx.

Du demi-additionneur à l'additionneur 1 bit[modifier | modifier le wikicode]

Lire Additionneur dans Wikipédia.

Exercice 1[modifier | modifier le wikicode]

1) Implanter un additionneur 1 bit avec deux LUTs. Pour les tests, les entrées seront reliées à des interrupteurs et les sorties à des LEDs.

2) Réaliser 4 fois le schéma précédent et montrer que l'on peut réaliser ainsi un additionneur 4 bits. N'oubliez pas que la somme de deux nombres de 4 bits peut donner un nombre de 5 bits. (Lire additionneur parallèle à propagation de retenue)

Additionneur 4 bits[modifier | modifier le wikicode]

Après avoir réalisé un additionneur 4 bits, on vous propose l'exercice ci-dessous. L'additionneur 4 bits est nommé 7483 dans le schéma.

Exercice 2 (transcodeur BCD vers EXCESS- 3)[modifier | modifier le wikicode]

Convertisseur décimal Excess 3 bidirectionnel

Code converter is a combinational circuit that translates the input code word into a new corresponding word. The excess-3 code digit is obtained by adding three to the corresponding BCD digit. To Construct a BCD-to-excess-3-code converter with a 4-bit adder feed BCD-code to the 4-bit adder as the first operand and then feed constant 3 as the second operand. The output is the corresponding excess-3 code.

Realize this circuit diagram in VHDL.

Indications :

  • Un transcodeur comme celui demandé peut être réalisé avec 4 LUT4. Mais remarquez que celui qui est proposé dans le schéma est bidirectionnel.
  • On pourrait utiliser le code ci-dessous pour l'additionneur 4 bits en lieu et place de celui qu'on a réalisé dans l'exercice 1 :
-- addition sur 4 bits
library IEEE; 
use IEEE.std_logic_1164.all; 
use IEEE.std_logic_arith.all; 
use IEEE.STD_LOGIC_UNSIGNED.all; 
ENTITY add4 IS
PORT (a,b : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
      Cin : IN STD_LOGIC; --retenue précédente
      s : OUT STD_LOGIC_VECTOR(4 DOWNTO 0)); --retenue en s(4)
END add4;

ARCHITECTURE arch_add4 OF add4 IS
BEGIN
-- ne pas confondre + avec OR
  s <=  conv_std_logic_vector((conv_integer(a) + conv_integer(b) + conv_integer(Cin)),5);
END arch_add4;

mais on vous demande plutôt d'utiliser la hiérarchie de l'exercice 1 pour obtenir une hiérarchie sur 3 niveau : le transcodeur qui contient un additionneur 4 bits qui contient 4 additionneurs 1 bit.

  • La table de vérité du code excess-3 est :
Table de vérité du code EXCESS-3
Entrées Sorties
B3 B2 B1 B0 E3 E2 E1 E0
0 0 0 0 0 0 1 1
0 0 0 1 0 1 0 0
0 0 1 0 0 1 0 1
0 0 1 1 0 1 1 0
0 1 0 0 0 1 1 1
0 1 0 1 1 0 0 0
0 1 1 0 1 0 0 1
0 1 1 1 1 0 1 0
1 0 0 0 1 0 1 1
1 0 0 1 1 1 0 0
1 0 1 0 Φ Φ Φ Φ
1 0 1 1 Φ Φ Φ Φ
1 1 0 0 Φ Φ Φ Φ
1 1 0 1 Φ Φ Φ Φ
1 1 1 0 Φ Φ Φ Φ
1 1 1 1 Φ Φ Φ Φ

Exercice 3[modifier | modifier le wikicode]

Comparateur 4 bits et son tableau de Karnaugh associé

Première partie[modifier | modifier le wikicode]

Réaliser une comparaison seule (figure ci-contre en remplaçant le "neuf" par des interrupteurs). Réaliser le fichier ucf pour utiliser sw7 ... sw0 en entrée et led0 en sortie (pour GT seulement). Tester.

Indication : Le comparateur COMPM4 présent dans cet exercice peut être réalisé par le code VHDL :

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.std_logic_unsigned.all;

entity COMPM4_exo3 is
  
port(
    GT  : out std_logic;
    LT  : out std_logic;

    A0  : in std_logic;
    A1  : in std_logic;
    A2  : in std_logic;
    A3  : in std_logic;
    B0  : in std_logic;
    B1  : in std_logic;
    B2  : in std_logic;
    B3  : in std_logic
  );
end COMPM4_exo3;

architecture COMPM4_exo3_V of COMPM4_exo3 is
  signal a_tmp: std_logic_vector(3 downto 0);
  signal b_tmp: std_logic_vector(3 downto 0);

begin

   a_tmp <= A3&A2&A1&A0;
   b_tmp <= B3&B2&B1&B0;
   
   GT <= '1' when (a_tmp > b_tmp ) else '0';
   LT <= '1' when (a_tmp < b_tmp ) else '0';
     
end COMPM4_exo3_V;
----- CELL CB4CE_HXILINX_chenillard -----

Pour bien comprendre ce code, il vous est demandé de remplacer les entrées par deux entrées a et b en std_logic_vector( 3 downto 0)

Deuxième partie[modifier | modifier le wikicode]

Puis fixer les entrées Bi à 9 pour en faire une fonction de 4 entrées A3,A2,A1,A0 comme dans la figure. Remplir une table de vérité puis un tableau de Karnaugh.

Table de vérité du comparateur à 9
Entrées Sorties
A3 A2 A1 A0 GT
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1
Table de Karnaugh
S A1 A0 00 01 11 10
A3 A2
00
01
11
10

1°) Déduire de la table de vérité une LUT4 réalisant l'ensemble. La câbler puis l'essayer dans le FPGA. Faire constater à l'enseignant.

2°) Déduire du tableau de Karnaugh une équation simplifiée que l'on implantera en VHDL.

Exercice 4 : additionneur complet (1 bit) et multiplexeur[modifier | modifier le wikicode]

Implement a full 1-bit adder

(a) using two 8-to-1 MUXes. Connect X,Y, and Cin in to the control inputs of the MUXes and connect 1 or 0 to each data input.

(b) using two 4-to-1 MUXes and one inverter. Connect X and Y to the control inputs of the MUXes, and connect 1’s, 0’s, Cin in , or Cin′ in to each data input.

(c) again using two 4-to-1 MUXes, but this time connect Cin in and Y to the control inputs of the MUXes, and connect 1’s, 0’s, X, or X′ to each data input. Note that in this fashion, any N-variable logic function may be implemented using a 2 (N−1) to-1 MUX.

Indication[modifier | modifier le wikicode]

Ce travail nécessite de réaliser un assemblage de circuits donc se fait avec des PORT MAP.

Voici le code de départ d'un multiplexeur 8 vers 1.

-- description du multiplexeur
library ieee;
use ieee.std_logic_1164.all;

entity mux8 is port (
	sel: in std_logic_vector(2 downto 0);
	e : in std_logic_vector(7 downto 0);
	s : out std_logic
	);
end entity mux8;
architecture behavior of mux8 is
begin
       with sel select 
                s <= e(0) when "000",
                     e(1) when "001",
                     e(2) when "010",
                     e(3) when "011",
                     e(4) when "100",
                     e(5) when "101",
                     e(6) when "110",
                     e(7) when others;
end behavior;

TP4 Introduction au séquentiel (3 heures)[modifier | modifier le wikicode]

Besoin d'une horloge pour dépasser le combinatoire[modifier | modifier le wikicode]

Les compteurs permettent de diminuer la fréquence d'horloge.

Exercice 1[modifier | modifier le wikicode]

Vous disposez d'une horloge 50MHz en broche "B8" de votre composant FPGA SPARTAN 3E. Réaliser à l'aide d'un compteur 24 bits une horloge d'environ 3 Hz. Sortie sur une LED, le clignotement de celle-ci doit être visible à l'œil.

Indications

  • Un exemple de compteur est donné ci-dessous. Il s'agit d'un compteur 8 bits. Vous devez donc l'adapter pour l'exercice 1 :
    • Changer le nom de l'entité, cmpt8bits ne correspondra plus à la fonction réalisée. cmpt24bits serait plus adapté
    • diminuer la taille de la sortie qui passe de 8 bits à un bit et l'appeler clk_slow par exemple
    • augmenter la taille du compteur qui passe de 8 bits à 24 bits
    • changer la toute dernière équation
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
ENTITY cmpt8bits IS
  PORT(clk : IN STD_LOGIC;
    cnt : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END cmpt8bits;
 
ARCHITECTURE arch_cmpt8bits OF cmpt8bits IS
  signal cmpt : std_logic_vector(7 downto 0);
BEGIN
  process(clk) begin
    if rising_edge(clk) then
      cmpt <= cmpt + 1;
    end if;
  end process;
  cnt <= cmpt;  
END arch_cmpt8bits;
  • Le fichier ucf est :
# clock pin for Basys2 Board 
NET "clk" LOC = "B8"; # Bank = 0, Signal name = MCLK 
### NET "clk_slow" CLOCK_DEDICATED_ROUTE = FALSE; 



Par abus de langage on appellera compteur dans la suite un élément séquentiel qui comporte une horloge mais qui ne compte pas forcément en binaire. Dans ce dernier cas, son équation de récurrence ne peut donc pas s'écrire simplement à l'aide d'une addition.

Réaliser un graphe d'évolution simple[modifier | modifier le wikicode]

Avant toute chose, il nous faut nous demander comment utiliser des équations de récurrences booléennes. On vous représente ci-après la façon de procéder :

  • trouver le diagramme d'évolution
  • en déduire le tableau état présent/état futur
  • en déduire les équations en utilisant éventuellement un tableau de Karnaugh

Lisez Des diagrammes d'évolutions aux équations de récurrences pour la partie théorique. Vous y trouverez les équations de récurrences nécessaires à la réalisation de l'exercice 2.

Exercice 2[modifier | modifier le wikicode]

Diagramme d'évolution de départ

1°) Realize the system specified above with a state diagram. The clock is, as usual, "clk_slow" (see l'exercise 1). Add two LEDs as outputs to be able to check your VHDL program.

2°) Design a modulo-4 counter with an input D, for Down. When D is not asserted, the counter counts up, modulo-4. When D is asserted (1), the counter counts down, modulo-4. Draw a state diagram to implement it and derive the state table. Then design a complete sequential circuit using VHDL. Please use a 7 segments display to check your VHDL code.

Indication : Si vous voulez avoir une chance de voir les LEDs défiler, vous devez utiliser le compteur de l'exercice 1 pour faire une horloge lente et l'utiliser comme entrée horloge de ce qui vous est demandé. Il y a donc du PORT MAP dans l'air.

library ieee;
use ieee.std_logic_1164.all;
ENTITY cmpt_exo2 IS PORT (
  clk: IN std_logic;
  q0,q1: OUT std_logic);
END cmpt_exo2;
ARCHITECTURE arch_cmpt_exo2 OF cmpt_exo2 IS
  SIGNAL q1q0 : std_logic_vector(1 downto 0);
BEGIN
  PROCESS (clk) BEGIN -- ou cmpt:PROCESS (clk) BEGIN
    IF (clk'EVENT AND clk='1') THEN
      q1q0(0) <= NOT q1q0(0);
      -- add the second equation here
    END IF;
  END PROCESS;
  -- mise a jour des sorties
  q0 <= q1q0(0);
  q1 <= q1q0(1);
END arch_cmpt_exo2;

Compteur décimal à sortie directe sept segments (1 digit en VHDL)[modifier | modifier le wikicode]

Le compteur sept segments est réalisé en VHDL et sera assemblé avec le dispositif destiné à réaliser l'horloge lente : compteur 24 bits de l'exercice 1.

Exercice 3[modifier | modifier le wikicode]

1°) Écrire les équations logiques a+, b+, c+, d+ ,e+, f+, g+ en fonction des entrées a, b, c, d, e, f, g. Implanter en VHDL.

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 
ENTITY cmpt7seg IS
  PORT(CLK_lent : IN STD_LOGIC;
  a,b,c,d,e,f,g : OUT STD_LOGIC);
-- ou  alors : s7segs : out std_logic_vector(6 downto 0));
END cmpt7seg;

Il nous reste un problème important à résoudre, c'est l'initialisation. En effet pour bien faire il faudrait étudier les 127-10=117 états restants pour voir comment ils se connectent sur notre cycle. C'est un travail important qu'il est impossible de réaliser à moins d'y passer 117 soirées (à raison d'une transition par soirée) soit presque 4 mois !!!

Pour éviter cela on va prévoir une entrée d'initialisation appelée Init au cas où à la mise sous tension on se trouve dans un état non prévu. Cette entrée fonctionnera de manière synchrone, lorsqu'elle sera à 1 un front d'horloge provoquera l'affichage du 0 en sortie du compteur.

2°) Écrire maintenant les équations de récurrence trouvées en 1°) en ajoutant convenablement l'entrée Init.

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 
ENTITY cmpt7seg IS
  PORT(CLK_lent, Init : IN STD_LOGIC;
  a,b,c,d,e,f,g : OUT STD_LOGIC);
-- ou  alors : s7segs : out std_logic_vector(6 downto 0));
END cmpt7seg;

Exercice 4[modifier | modifier le wikicode]

Refaire le même travail que l'exo4 en utilisant un case when et toujours "clk_slow" comme horloge.

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 
ENTITY cmpt7seg IS
  PORT(CLK_lent : IN STD_LOGIC;
  s_7segs : OUT STD_LOGIC_VECTOR(6 DOWNTO 0));
END cmpt7seg;

Remarquez l'utilisation du STD_LOGIC_VECTOR au lieu des sorties individuelles. Le fait qu'il soit en OUT implique que l'on utilisera un signal interne pour les "CASE".

Indication : Implanter un diagramme d'évolution en VHDL peut se faire de manière systématique :

LogiqueSequ1.png
library ieee;
use ieee.std_logic_1164.all;
ENTITY demo IS PORT(
  clock : IN std_logic;
  q : OUT std_logic_VECTOR(1 DOWNTO 0));
END demo;

ARCHITECTURE mydemo OF demo IS
  SIGNAL q1q0 : std_logic_vector(1 downto 0);
BEGIN
   PROCESS(clock) BEGIN
     IF clock'EVENT AND clock='1' THEN
      CASE q1q0 IS  --style case when
        WHEN "00" => q1q0 <="01"; 
        WHEN "01" => q1q0 <="10"; 
        WHEN "10" => q1q0 <="11"; 
        WHEN OTHERS => q1q0 <="00" ;
      END CASE;
     END IF;
   END PROCESS;
   q <= q1q0; 
END mydemo;

TP5 M1102 : VHDL et Compteurs[modifier | modifier le wikicode]

Exercice 1[modifier | modifier le wikicode]

Cet exercice ne sera réalisé que par les étudiants qui ne sont pas allés jusqu'au bout du TP 4.

Nous vous donnons deux composants VHDL et on vous demande d'en réaliser un assemblage.

On vous donne les deux composants VHDL suivants. On vous demande de les assembler (en complétant les transitions de « cmpt7seg » ) dans un programme TOP.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
ENTITY cmpt24bits IS
  PORT(clk_50MHz : IN STD_LOGIC;
    clk_slow : OUT STD_LOGIC);
END cmpt24bits;
 
ARCHITECTURE acmpt24bits OF cmpt24bits IS
  signal cmpt : std_logic_vector(23 downto 0);
BEGIN
  process(clk_50MHz) begin
    if rising_edge(clk_50MHz) then
      cmpt <= cmpt + 1;
    end if;
  end process;
  clk_slow <= cmpt(23);  
END acmpt24bits;
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
ENTITY cmpt7seg IS
  PORT(CLK : IN STD_LOGIC;
    s_7segs : OUT STD_LOGIC_VECTOR(6 DOWNTO 0));
END cmpt7seg;
ARCHITECTURE arch OF cmpt7seg IS -- comment éviter les equations
  SIGNAL s7segs : STD_LOGIC_VECTOR(6 DOWNTO 0);
BEGIN
  PROCESS(clk) BEGIN
    IF (clk'EVENT AND clk='1') THEN
     CASE s7segs is --style case when
       WHEN "0000001" => s7segs <="???????"; -- premiere transition 
       WHEN "1001111" => s7segs <="???????"; -- deuxieme transition
       WHEN "0010010" => s7segs <="???????"; -- troisieme transition
       WHEN "0000110" => s7segs <="???????";
       WHEN "1011100" => s7segs <="???????";
       WHEN "0100100" => s7segs <="???????";
       WHEN "0100000" => s7segs <="???????";
       WHEN "0001111" => s7segs <="???????";
       WHEN "0000000" => s7segs <="???????";
       WHEN OTHERS => s7segs <="0000001"; -- dernière transition
     END CASE;
   END IF;
  END PROCESS;
  s_7segs <=s7segs;
END arch;

Nous allons reprendre le problème du compteur sept segments mais de façon plus normale.

Compteur à sortie sept segments sur deux digits en VHDL[modifier | modifier le wikicode]

Cette partie doit être réalisée avec les afficheurs sept segments reliés à la carte.

Nous allons réaliser cet exercice en plusieurs étapes.

Exercice 2[modifier | modifier le wikicode]

Nous désirons implanter un ensemble composé d'un compteur 8 bits et sortant sa valeur sur deux afficheurs sept segments ( affichage de 00 à FF)...

Attention, le poids faible doit être à droite !!!

Affichage d'un compteur 8 bits en hexadécimal

1°) Réaliser d'abord un compteur simple 8 bit associé à une division par 2**24 et sortant directement sur des LEDs. La seule entrée est clk qui se trouve en "B8" sur le FPGA. Les 8 sorties sont reliées aux 8 LEDs de la carte. Remarquez que le seul compteur qui nous intéresse est le compteur 8 bits de droite, l'autre étant là pour ralentir l'horloge.

2°) Réaliser maintenant l'affichage des 4 bits de poids faibles sur un seul afficheur.

3°) Réaliser maintenant l'affichage des 8 bits du compteur sur deux afficheurs. La figure donne en principe ce que l'on cherche à faire et l'idéal serait de la comprendre.

Indications :

  • Vous devriez avoir sauvegardé depuis longtemps le transcodeur :
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
ENTITY transcod7segs IS PORT(
  e : in std_logic_vector(3 downto 0);
  s7segs : out std_logic_vector(6 downto 0));
END transcod7segs;
ARCHITECTURE arch of transcod7segs IS 
BEGIN
  with e select
             --abcdefg
    s7segs <= "0000001" when "0000",
              "1001111" when "0001",
              "0010010" when "0010",
              "0000110" when "0011",
              "1001100" when "0100",
              "0100100" when "0101",
              "0100000" when "0110",
              "0001111" when "0111",
              "0000000" when "1000",
              "0000100" when "1001",
              "0001000" when "1010",
              "1100000" when "1011",
              "0110001" when "1100",
              "1000010" when "1101",
              "0110000" when "1110",
              "0111000" when others;
END;
  • le multiplexeur peut être réalisé par :
with sel select
  s4 <= entrees8(3 downto 0) when '1',
        entrees8(7 downto 4) when others;

que vous compléterez pour en faire une architecture puis ajouterez une entité.

  • les sorties an sont gérées avec des équations
an3 <= '1';
an2 <= '1';
an1 <= s_sel;
an0 <= not s_sel;

Compteur BCD sur deux digits[modifier | modifier le wikicode]

Nous cherchons maintenant à modifier le compteur de l'exercice précédent (exercice 2) pour qu'il affiche de 00 à 99.

Exercice 3[modifier | modifier le wikicode]

Réaliser un compteur BCD 4 bits cascadable. Il sera ensuite cascadé pour fournir un compteur BCD sur 8 bits (deux digits).

Indication : une aide pour réaliser un compteur BCD vous est présentée. Vous devez le modifier pour le rendre cascadable.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity CounterBCD is
   port( EN: in std_logic;
 	 Clock: in std_logic;
 	 Reset: in std_logic;
--         ENO : out std_logic;
 	 Output: out std_logic_vector(3 downto 0));
end CounterBCD;
 
architecture Behavioral of CounterBCD is
   signal cmpt: std_logic_vector(3 downto 0);
begin   process(Clock,Reset)
   begin
      if Reset='1' then
         cmpt <= "0000";
      elsif(rising_edge(Clock)) then
 	 if EN='1' then
	    if cmpt="1001" then
	       cmpt<="0000";
	    else
	       cmpt <= cmpt + 1;
	    end if;
         end if;
      end if;
   end process;
   Output <= cmpt;
end Behavioral;

La réalisation de ENO étant combinatoire, on vous demande de le réaliser avec un with select when. En remarquant que ENO est à 1 si EN=1 et cmpt=9, il est possible de réaliser une concaténation du signal pour l'utiliser dans le with select when. Voici le tout en image :

  s_en_cmpt <= en & cmpt;
  with s_en_cmpt select
    ENO <= '1' when "?????",
           '0' when others;

Exercice 4 Compteur/décompteur BCD sur deux digits[modifier | modifier le wikicode]

Réaliser un compteur/décompteur BCD 4 bits. Prévoir les tests correspondants à partir du schéma de l'exercice 2.

Indication : une aide pour réaliser un compteur décompteur BCD cascadable peut être trouvée ici.

TP6 : Mémoires[modifier | modifier le wikicode]

Le réveil[modifier | modifier le wikicode]

Le diagramme d'évolution comme moyen de spécifier le calcul de l'état futur en fonction de l'état présent

Dans la partie droite de la figure ci-dessus, vous pouvez apercevoir le diagramme d'évolution du réveil qui sera utilisé comme exemple par la suite.

Principe de fonctionnement du réveil : à partir de "Off", "key"=1 arme le réveil. Si "trip" passe à 1 (c'est à dire que l'heure courante devient égale à l'heure de réveil) le réveil passe en "ringing" et sonne. "trip" ne reste pas très longtemps à un (1 seconde). Son retour à 0 ne suffit pas à arrêter la sonnerie. Seul le passage de "key" à 0 peut l'arrêter.

Les graphes d'évolutions et le style « case when »[modifier | modifier le wikicode]

On rappelle encore une fois que le style « case when » permet de ne pas chercher les équations de récurrences. Mais comme nos diagrammes d'évolutions se sont compliqués (par l'ajout d'étiquettes sur les transitions), il nous faudra ajouter des "if then". Cela est tellement intuitif que nous passons directement aux exemples. Nous commençons par présenter partiellement le réveil.

Programmation sans initialisation[modifier | modifier le wikicode]

Le principe consiste à déclarer d'abord un type énuméré avec une définition symbolique de chacun des états (ici Armed, Off, Ringing) :

TYPE typetat IS (Armed, Off, Ringing); -- dans architecture
SIGNAL etat : typetat;

Ensuite dans un « case when » on détaillera toutes les transitions possibles comme montré ci-dessous dans le cas où l'on ne s'intéresse pas à une initialisation :

-- sans initialisation
BEGIN
  PROCESS (clock) BEGIN
    IF clock'EVENT AND clock='1' THEN
      CASE etat IS
      WHEN Off => IF key ='1' THEN etat <= Armed; 
                  ELSE etat <= Off; 
                  END IF;
                  ....
      END CASE;
    END IF;
  END PROCESS;
  ....

L'idée générale est donc d'utiliser un « case » sur les états avec des « if » pour gérer l'ensemble des transitions.

Exercice 1[modifier | modifier le wikicode]

Réaliser le réveil ci-dessus en n'oubliant pas de ralentir l'horloge du séquenceur pour éviter les problèmes de rebonds.

Indications :

  • Vous aurez deux boutons en entrée :
    • un bouton d'armement du réveil appelé key dans le diagramme d'évolution
    • un bouton simulant l'égalité entre heure réveil et heure courante appelé Trip dans le diagramme d'évolution
  • Vous avez naturellement l'horloge en entrée qui peut être branchée sur la sortie d'un habituel compteur 24 bits que l'on peut trouver dans cette page.
  • La sonnerie du réveil sera une simple LED

Compteur à sortie sept segments avec mémoire[modifier | modifier le wikicode]

Nous allons utiliser un compteur normal, c'est à dire qui compte en binaire sur 4 bits suivi d'une mémoire pour le transcodage.

Présentation des RAM16X8S[modifier | modifier le wikicode]

Pour les utiliser, il ne pas oublier les lignes

library UNISIM;
use UNISIM.Vcomponents.ALL;

devant toute entité qui utilise ces mémoires.

Le composant correspondant est (donné ici pour information) :

  component RAM16X8S
      -- synopsys translate_off
      generic( INIT_00 : bit_vector :=  x"0000";
               INIT_01 : bit_vector :=  x"0000";
               INIT_02 : bit_vector :=  x"0000";
               INIT_03 : bit_vector :=  x"0000";
               INIT_04 : bit_vector :=  x"0000";
               INIT_05 : bit_vector :=  x"0000";
               INIT_06 : bit_vector :=  x"0000";
               INIT_07 : bit_vector :=  x"0000");
      -- synopsys translate_on
      port ( A0   : in    std_logic; 
             A1   : in    std_logic; 
             A2   : in    std_logic; 
             A3   : in    std_logic; 
             D    : in    std_logic_vector (7 downto 0); 
             WCLK : in    std_logic; 
             WE   : in    std_logic; 
             O    : out   std_logic_vector (7 downto 0));
   end component;

Il n'est pas à déclarer puisque c'est justement les deux lignes qu'on a rajouté qui le fait. Par contre toute utilisation nécessite un "PORT MAP" précédé par un "GENERIC MAP".

Exercice 2 Travail à réaliser (VHDL)[modifier | modifier le wikicode]

Réalisation d'un transcodage par mémoire RAM initialisée

Calculer les valeurs hexadécimales contenues dans cette ROM RAM16X8S pour réaliser le transcodage qui convient.

Reprendre le diviseur de fréquence par 2**24.

Assembler le tout.

Indications : Partez du programme ci-dessous en complétant tous les points d'interrogations et les entités et architecture de ce qui manque, à savoir le compteur 24 bits et le compteur 4 bits.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- pour la mémoire
library UNISIM;
use UNISIM.Vcomponents.ALL;
entity top is port(
  clk50 : in std_logic;
  s7segs : out std_logic_vector(7 downto 0);
  an : out std_logic_vector(3 downto 0));
end top;

architecture arch_top of top is
COMPONENT cmpt4bits IS
  PORT(clk : IN STD_LOGIC;
       Q : OUT STD_LOGIC_VECTOR(3 DOWNTO 0));
END COMPONENT;
COMPONENT cmpt24bits IS
  PORT(clk_50MHz : IN STD_LOGIC;
    clk_slow : OUT STD_LOGIC);
END COMPONENT;
  SIGNAL s_clk_slow : std_logic;
  SIGNAL s_Q : std_logic_vector(3 downto 0);
begin
  lent: cmpt24bits port map(
           clk_50MHz => ????,
           clk_slow => ???);
  cmpt: cmpt4bits port map(
           clk => ????,
           Q => s_Q);
  ram:RAM16X8S 
      ---- synopsys translate_off
      generic map( INIT_00 =>  x"????", -- a
               INIT_01 =>  x"????", -- b
               INIT_02 =>  x"????", -- c
               INIT_03 =>  x"????", -- d
               INIT_04 =>  x"????", -- e
               INIT_05 =>  x"????", -- f
               INIT_06 =>  x"????", -- g
               INIT_07 =>  x"FFFF")
      ---- synopsys translate_on
      port map( A0   => ??? ,
             A1   => ??? , 
             A2   => ??? , 
             A3   => ??? , 
             D    => "00000000",
             WCLK => '0' ,
             WE   => '0' , 
             O    => ???);
  an <= "1110";
end arch_top;

Exercice 3 : Texte défilant[modifier | modifier le wikicode]

Donner le contenu de la RAM pour afficher le texte : "bonjour A touS" qui défile sur un afficheur.

Réaliser l'ensemble et tester. Faire constater.

Indication : Il n'y a que très peu de choses à changer par rapport à l'exercice 2.

Exercice 4 : Chenillard sur LEDs[modifier | modifier le wikicode]

Ensemble destiné à réaliser un chenillard

1°) On reprend l'exercice précédent mais on sort maintenant sur 8 LEDs (schéma ci-contre). On vous demande de réaliser un chenillard aller et retour. Il faut donc changer le fichier ucf et le contenu de la RAM16X8S.

2°) DS 2014. Les sorties précédentes sont maintenant utilisées comme adresses d'une RAM16x8s comme dans la figure ci-contre. Donner le contenu de la RAM pour afficher le chenillard ci-contre. Réaliser l'ensemble et tester. Faire constater.

Chenillar à réaliser avec RAM

Autre métode pour utiliser des RAMs[modifier | modifier le wikicode]

Si vous voulez que votre outil de synthèse infère une RAM/ROM il vous faut écrire votre RAM/ROM avec un style spécifique. Nous présentons ici un exemple sur lequel nous nous appuierons dans la suite : ROM avec sortie Registered

 
-- 
-- ROMs Using Block RAM Resources. 
-- VHDL code for a ROM with registered output (template 1) 
-- 
library ieee; 
use ieee.std_logic_1164.all; 
use ieee.std_logic_unsigned.all; 
entity rams_21a is 
    port (clk : in std_logic; 
           en    : in std_logic; 
           addr : in std_logic_vector(5 downto 0); 
           data : out std_logic_vector(19 downto 0)); 
end rams_21a; 
architecture syn of rams_21a is 
  type rom_type is array (63 downto 0) of std_logic_vector (19 downto 0); 
  signal ROM : rom_type:= 
    (X"0200A", X"00300", X"08101", X"04000", X"08601",   X"0233A", 
     X"00300", X"08602", X"02310", X"0203B", X"08300", X"04002", 
     X"08201", X"00500", X"04001", X"02500", X"00340", X"00241", 
     X"04002", X"08300", X"08201", X"00500", X"08101", X"00602", 
     X"04003", X"0241E", X"00301", X"00102", X"02122", X"02021", 
     X"00301", X"00102", X"02222", X"04001", X"00342", X"0232B", 
     X"00900", X"00302", X"00102", X"04002", X"00900", X"08201", 
     X"02023", X"00303", X"02433", X"00301", X"04004", X"00301", 
     X"00102", X"02137", X"02036", X"00301", X"00102", X"02237", 
     X"04004", X"00304", X"04040", X"02500", X"02500", X"02500", 
     X"0030D", X"02341", X"08201", X"0400D"); 
begin 
    process (clk) 
    begin 
        if (clk'event and clk = '1') then 
             if (en = '1') then 
                  data <= ROM(conv_integer(addr)); 
             end if; 
         end if; 
    end process; 
end syn;

Exercice 5 : Travail à réaliser[modifier | modifier le wikicode]

On transcode maintenant avec une ROM

1°) En partant de l'exercice 2, on vous demande de modifier toute la partie mémoire : on n'utilisera plus la RAM16X8S mais une ROM décrit en VHDL comme ci-dessus. Assembler le tout, vérifier.

2°) En partant de l'exercice 3, on vous demande de modifier toute la partie mémoire : on n'utilisera plus la RAM16X8S mais une ROM décrit en VHDL comme ci-dessus. Assembler le tout, vérifier.

3°) Pouvez-vous imaginer une architecture qui fasse défiler le texte sur 4 digits.

Exercice 6 : Barregraphe sur LEDs[modifier | modifier le wikicode]

On désire afficher une valeur de 0 (tout éteint) à 8 (tout allumé) sur les 8 LEDs. Toute valeur supérieure à 8 affichera 8 (effet de saturation).

  1. Expliquer pourquoi on doit prendre une RAM16X8S.
  2. Calculer son contenu et tester avec le même schéma que exo2.
  3. Implanter et tester en prenant un compteur qui compte de 0 à 8 seulement.
  4. On complique maintenant le compteur. Il devient un compteur/décompteur.