Vous êtes sur la page 1sur 15

Cité Scientifique 59655 Villeneuve d'Ascq Cedex Tél. +33 (0) 3.20.43.43.

43

Licence 3 LIE – Semestre 5

Electronique numérique [EN]

Deuxième partie

Synthèse de circuits numériques à l’aide de VHDL et implantation dans un FPGA

D. Gaillot

N. Bourzgui
Bât. P4 Bur. 209

1
2
1. Fonctions séquentielles

Les sorties d’un système séquentiel dépendent :

 De l’état présent du système (machine de Moore)


 De l’état présent et des entrées du système (machine de Mealy)

Dans les systèmes séquentiels, la mémorisation de l’état des sorties est réalisée par des bascules. Au front
actif d’une horloge de cadencement (un signal carré de fréquence généralement fixe et stable), l’état des
sorties change. Le nouvel état dépend de l’état précédent et des éventuelles entrées.

1.1 Division de fréquence par 2, exemple de la bascule D

Description VHDL d’une bascule D

Au front d’horloge, la sortie q recopie l’entrée d.


d q

H Entre 2 fronts d’horloge, la sortie q est figée ce qui permet de


garder en mémoire l’état de d.
clk

Déclaration des bibliothèques et de l'entité

La bibliothèque IEEE est déclarée pour utiliser le type std_logic ainsi que la fonction rising_edge qui
permet de détecter un front montant sur un signal. En logique synchrone, seul le signal d'horloge va utiliser
cette fonction.

LIBRARY IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

ENTITY dff IS
PORT (
clk : IN std_logic;
d: IN std_logic;
q: OUT std_logic
);
END dff ;

ARCHITECTURE arc OF dff IS


BEGIN
PROCESS (clk)
BEGIN
IF RISING_EDGE (clk) THEN q <= d;
END IF;
END PROCESS;
END arc;

Description de l’architecture
3
Le codage comportemental de la bascule fait appel à un processus (PROCESS). Un processus est un
enchaînement d'instructions décrivant un comportement. Il possède une liste de sensibilité spécifiant sur
quel signal le processus doit s'exécuter. Le processus en soit est une instruction concurrente mais son
contenu est une suite d'instructions séquentielles. Il peut être utilisé aussi bien pour la logique séquentielle
que pour la logique combinatoire.
Dans le cas de la logique synchrone faisant des calculs au rythme d'une horloge clk, la syntaxe est donc
PROCESS (clk)
Enfin, le corps du processus, codé entre BEGIN et END PROCES, contient les instructions à exécuter, Pour
une bascule D, cela consiste à recopier la valeur de l'entrée sur la sortie.
q <= d;
Il faut préalablement tester le front sur lequel l'exécution a lieu en utilisant l'instruction :
IF clk=’1’ AND CLK’EVENT THEN.
ou, si on utilise la bibliothèque IEEE: IF RISING_EDGE (clk) THEN

Faire une simulation fonctionnelle de la bascule D (l'horloge clk sera fixée à 20 ns de période par la grille,
Pour accéder à la grille lorsque le fichier de simulation .vwf est actif « edit Grid Size… » ), programmer et
tester la bascule D (utiliser le bouton poussoir pour l’horloge avec visualisation de l’état à l’aide d’une
LED).

Dans le cas où on boucle (/Q : not(Q)) sur l’entrée D, quel rapport existe t-il entre la fréquence du signal clk
et celle de la sortie Q?, écrire le code et faire la simulation avec un Reset (Clear) et un set (Preset), le reset
doit être prioritaire sur le set.

1.2 Compteur avec Reset asynchrone

Déclaration des bibliothèques et de l'entité


Le compteur dispose d'une entrée reset asynchrone resetn et d'une sortie q sur 4 bits.

LIBRARY IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

ENTITY compteur4 IS
PORT (
clk : IN std_logic ;
resetn : IN std_logic ;
q: OUT unsigned (3 downto 0)
);
END compteur4 ;

ARCHITECTURE archi OF compteur4 IS


SIGNAL q_int : unsigned(3 downto 0) ;
BEGIN
4
PROCESS (clk, resetn)
BEGIN
IF resetn = '0' THEN q_int <= (others => '0') ;
ELSIF rising_edge (clk) THEN q_int <= q_int + 1 ;
END IF ;
END PROCESS ;
q <= q_int ;
END archi ;

Description de l’architecture

La déclaration du signal interne q_int est nécessaire car q est un port de sortie, il ne peut donc pas être
utilisé en entrée pour réaliser l'instruction de comptage :
q <= q + 1
C'est q_int qui va donc servir à cette fin. Une autre solution aurait été de déclarer le port q de type buffer à
la place de out, ce qui aurait évité l'utilisation de q_int.

La valeur du compteur peut changer sur deux événements:


• front montant de l'horloge
• état bas du reset

La liste de sensibilité doit donc contenir ces 2 signaux: PROCESS (clk, resetn)

Conformément à l'utilisation du reset asynchrone sur les bascules, le signal resetn est prioritaire par rapport
au front d'horloge, il faut donc commencer le codage du processus par l'instruction : IF resetn = '0' THEN

Il aurait été possible de mettre à zéro q_int par l'instruction q_int <= « 0000 » ; mais l'instruction :
q_int <= (others => '0'); est plus générique. Il faut ensuite indiquer la condition sur le front montant de
l'horloge pour déclencher le comptage : ELSIF rising_edge (clk) THEN

Il faut noter que l'instruction de comptage s'effectue en additionnant un signal unsigned sur 4 bits avec un
entier : q_int <= q_int + 1 ; qui est une opération définie dans le paquetage numeric_std de IEEE.

L'addition entre un unsigned et un std_logic n'est pas définie (donc l'écriture q_int <= q_int + ‘1’ ; n'est
pas possible).

 Faire une simulation fonctionnelle du compteur 4 bits


 Quel rapport existe t-il entre les fréquences des différents signaux q[3], q[2], q[1] et q[0]. Déterminer
alors la fonction réalisée dans ce cas.
 Si on considère que le bus q[3..0] comprenant les signaux q[3], q[2], q[1] et q[0] représente un
nombre binaire, quelle fonction réalise-t-on maintenant ?
 Reprendre la compilation, mais cette fois avec une simulation temporelle (horloge de période 20 ns).
Que remarque t- on ? Conclusion ?
CMP4BITS

RESET Q[3..0]
CLOCK
LOAD
SENS
DATA[3..0]

inst4

 Ecrire le code vhdl d’un compteur / décompteur 4 bits avec :


Remise à zéro asynchrone du compteur (RESET)
5
Rechargement synchrone (si « LOAD =’1’ alors on transfert l’entrée DATA en sortie Q)
Incrémentation (SENS =’1’) et Décrémentation (SENS =’0’) synchrones.
Vérifier votre code vhdl par une simulation fonctionnelle puis tester le circuit à l’aide du FPGA.
(Utiliser le bouton poussoir pour l’horloge avec visualisation de l’état à l’aide d’une LED).

1.3 Registre à décalage

On cherche à réaliser un registre à décalage sur 4 bits, possédant une sortie supplémentaire (match) active à
‘1’ si le contenu du registre à décalage vaut une valeur précise (vall).

Déclaration des bibliothèques et de l'entité

Le port d'entrée d_in rentre dans un registre à décalage de 4 bits qui sort sur d_out. La sortie match est
activée à 1 lorsque l'entrée vall est égale au contenu du registre à décalage.

registre4

clk d_out
d_in match
v all[3..0]

inst1

LIBRARY IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

ENTITY registre4 IS
PORT (
clk : IN std_logic ;
d_in : IN std_logic ;
vall : IN UNSIGNED (3 downto 0) ;
d_out : OUT std_logic ;
match : OUT std_logic
);
END registre4 ;

ARCHITECTURE archi OF registre4 IS


signal reg : unsigned(3 downto 0) ;
BEGIN
PROCESS (clk)
BEGIN
IF rising_edge (clk) THEN
reg(0) <= d_in ;
reg(3 downto 1) <= reg(2 downto 0) ;
END IF ;
END PROCESS ;
d_out <= reg (3);
match <= ‘1’ when vall = reg else ‘0’ ;
END archi ;

Processus synchrone de décalage :


La déclaration du signal reg est nécessaire pour définir les 4 bascules internes nécessaires au décalage, un
processus synchrone (donc sensible à clk) est utilisé. Les instructions d'affectations utilisées dans le
processus sont exécutées séquentiellement. L'exécution consiste à remplir un échéancier d'affectation et non
6
à affecter immédiatement le signal. Les affectations des signaux sont différées elles ne prendront effet
qu'une fois que tous les processus auront été exécutés, c'est à dire un temps symbolique après le front
montant d'horloge dans notre cas.

Il aurait été possible de regrouper ces 2 instructions en une seule :


reg(0) <= d_in ; reg(3 downto 1) <= reg(2 downto 0) ; par reg <= reg(2 downto 0) & d_in ;

Processus combinatoire :
La génération de la sortie match est un processus combinatoire, de même pour d_out qui est équivalent à
reg (3).

 Faire une simulation fonctionnelle du registre 4 bits.


 Programmation du FPGA et test
Modifier le programme pour faire une transformation série d_in (flux de données en entrée) => sortie
parallèle d_out de 4 bits avec la possibilité de RESET asynchrone.

7
Mini-Projet : Synthèse numérique de Fréquence

1. Principe de base :

La synthèse numérique de fréquence est l’incrémentation à fréquence fixe par une horloge à
quartz, d’un compteur dont la sortie va lire une mémoire morte (adresse de la mémoire). Si dans
celle-ci, à chaque adresse associée à l’incrément de temps, se trouve l’amplitude du signal
souhaité, après conversion numérique analogique, on obtient le signal recherché.

Dans le cas d’un signal sinusoïdal, les données de la mémoire peuvent être vues comme
l’amplitude associée à chaque phase instantanée du signal, et les adresses comme la phase du
signal.
Le schéma ci-après représente un compteur 8 bits incrémentant une mémoire Rom.

Le tableau suivant permet de comprendre le fonctionnement :

Front montant Sortie compteur = Sortie de la mémoire


De l’horloge Adresse mémoire Contenu de l’adresse
00000000 A0
00000001 A1
00000010 A2
00000011 A3
00000100 A4
00000101 A5
00000110 A6
…………. …………
11111111 A255
Entre chaque front montant de l’horloge nous avons une période d’horloge (Th), c’est le temps
entre deux amplitudes successives AiAj du signal sinusoïdal.

La période du signal en sortie de la mémoire :

Ts = Th * 28 = Th * 256

Donc la fréquence du signal en sortie dépend


de la fréquence de l’horloge.

8
Avant d’implanter ce schéma dans un projet Quartus, il nous faut d’abord déterminer les données
(amplitude du signal) à placer dans la mémoire (lors de l’implantation d’une ROM, Quartus impose
de connaître ces données).

2. Initialisation de la mémoire

L’implantation des données en mémoire se fait en déclarant un fichier d’initialisation au moment


de l’implantation de la mémoire dans la feuille de description graphique.
Ce fichier, d’extension « .mif », pour « memory initialization file », est un fichier texte précisant la
valeur de chaque mot à chaque adresse. Pour obtenir des informations sur le format souhaité,
taper « Memory Initialization File (.mif) Definition » dans la recherche de l’aide en ligne de
Quartus. Observer la structure de ce type de fichier.

Pour générer le fichier « .mif », il est possible d’entrer les 256 valeurs une par une (Quartus
propose un éditeur de fichier .mif, mais n’importe quel éditeur de texte ferait l’affaire aussi), nous
allons les générer automatiquement à l’aide du logiciel Scilab.

Ouvrir le logiciel Scilab, faire le changement du répertoire courant vers le répertoire du projet
Quartus et entrer le script suivant :

// programme d’écriture d'un fichier mémoire


//
clear;
//
// définition des 256 incréments de phase correspondant aux adresses
// et mise sous forme de vecteur colonne
//
ft=0:255 ; ft=ft' ;
//
// calcul du contenu de la mémoire, sinusoïde centrée sur le milieu de la dynamique des valeurs
//
x=127*(1+sin(2*%pi*ft/256));
//
// création et ouverture d’un fichier « mem.mif » en écriture
//
fd=mopen("mem.mif","w");
//
// écriture des adresses et données, sous forme d’entiers (%i), avec caractère de tabulation (\t)
// séparées par « : » et ligne terminée par « ; », puis retour à la ligne (\n)
//
mfprintf(fd,"\t%i : \t%i \t ; \n",ft,x);
//
// fermeture du fichier
//
mclose(fd);

Ouvrir ensuite le fichier mem.mif créé à l’aide de Scilab avec l’éditeur Notepad par exemple. Celui
de Quartus ne convient cependant pas car il cherchera pour un fichier .mif la syntaxe que nous
allons placer par la suite.

0 : 127 ;
1 : 130 ;
2 : 133 ;
…………………………………….
9
252 : 114 ;
253 : 117 ;
254 : 120 ;
255 : 123 ;

Modifier alors le fichier de manière à le rendre compatible avec un fichier « .mif » avec rajout
d’entête et end à la fin. On obtient finalement ceci :

DEPTH = 256;
WIDTH = 8;
ADDRESS_RADIX =DEC;
DATA_RADIX =DEC;
CONTENT
BEGIN
0 : 127 ;
1 : 130 ;
2 : 133 ;
3 : 136 ;
4 : 139 ;
………………………………………..
252 : 114 ;
253 : 117 ;
254 : 120 ;
255 : 123 ;
END;

il maintenant possible d’ouvrir le fichier avec l’éditeur de Quartus.

3. conception du synthétiseur de fréquence :


10
Ce projet sera réalisé en utilisant les méga-fonctions de Quartus II et une description graphique
pour la synthèse du circuit.
Ouvrir un nouveau projet nommé par exemple oscillateur, puis une nouvelle feuille graphique
(Block diagram/schematic File) (.bdf) et y implanter le compteur et la mémoire, par le biais des
composants prédéfinis (clic droit dans la feuille, puis Enter Symbol). Nous utiliserons :

- le composant LPM_COUNTER de la bibliothèque c:\..\megafunction\arithmetic\ pour le


compteur ; la fenêtre qui s’ouvre alors permet de définir un compteur 8 bits, avec une horloge
comme seul signal d’entrée (pas d’autres options) ;

- la mémoire ROM LPM_ROM de la même bibliothèque c:\..\megafunction\storage; Paramétrer


une mémoire de 256 mots de 8 bits, avec une seule horloge, déclarer le fichier mem.mif.
Paramétrage du compteur :

Paramétrage de la mémoire :

11
Après c’est Next puis Next

Placer les ports d’entrées et de sortie, faire une compilation en vue de simulation fonctionnelle.
On notera lors de la simulation le temps de latence de deux coups d’horloge entre l’application
d’une adresse (sortie compteur) et la présence de la sortie correspondante en mémoire.
On vérifie bien que les données inscrites en mémoire se retrouvent en sortie lorsque leur adresse
est présente sur le bus (revoir les premières lignes du fichier d'initialisation).

Visualisation de la sortie sous forme analogique :

12
Ce qui va nécessiter de réécrire sur le vecteur de simulation :

Puis en demandant de nouveau l’affichage sous forme analogique la fenêtre suivante apparait :

Il faudrait augmenter le temps de simulation pour faire


apparaitre quelques périodes (Edit => End Time…) par exemple 10µs pour une grille (Grid Size…)
de 10ns.

Utilisation d’un CNA externe


Pour visualiser le signal généré en sortie de la mémoire, il faudra la rediriger vers le CNA ainsi
que l’horloge. Le convertisseur numérique analogique de référence H15660IBZ (8 bits) capable
de travailler à une fréquence allant jusque 125MH est câblé sur une carte permettant de le relier à
l’aide d’une nappe à la carte DE1 d’Altera. Voir le schéma en dessous.

13
Schéma circuit du convertisseur numérique analogique

OUTPUT q[7..0]

lpm_counter0
up counter lpm_rom0
hor INPUT
VCC clock
q[7..0] address[7..0] OUTPUT sor[7..0]
PIN_B12 q[7..0]
inst1 clock
PIN_H12
LSB
inst PIN_H13
PIN_H14
OUTPUT hor_cna PIN_G15
PIN_E14
PIN_F12
PIN_E15
PIN_F15
PIN_G16
MSB

Assignements des pins avec le connecteur GPIO 1


On obtient bien une sinusoïde centrée sur le milieu de la dynamique.
La mémoire contenant 28 incréments de phase, adressé à une fréquence de 24 MHz, on trouve
donc en sortie une fréquence de 24 MHz/28 soit 93,75 kHz (10,66 µs).
Faire le montage et relever les caractéristiques du signal obtenu en termes d’amplitude, fréquence
spectre…
Annexe : Quartus II
1. Le projet

Créer un projet :
File > New Project Wizard

Afficher le « project navigator »


View > Utility Window>Project Navigator

Ajouter des fichiers au projet


Project > Add/Remove File in project

Changer la configuration du Projet (Device, etc….)


Assignement > Settings

Modifier l’ENTITY qui est en « Top Level »


Clic droit sur le fichier VHDL > Set as Top Level Entity

14
Créer une MegaFunction
Tool > MegaFunction Plug-in Manager

2. Compilation

Compiler :
Compilation > Start Compilation (compilation complète du projet)
Compilation > Analyse Current File (compilation du fichier courant)

Afficher le rapport de compilation


Processing > Compilation Report

Afficher le schéma RTL


Tool > Netlist Viewer > RTL Viewer

Affectation des broches du composant


Assignement > Assignement Editor
From : Vide
To > Node Finder > List > OK
Assignment Name > Location (Accept wildcards / groups)
Value : Valeur de la PIN

Créer un composant relatif au code VHDL écrit


Clic droit sur le fichier VHDL > Create Symbol File for Current File

Placer un composant sur le schématic


Edit > Insert Symbol

3. Simulation

Créer un fichier Waveform


File > New Simulation Input File

Insérer un signal
Clic droit dans la colone “Name” > Insert node or bus > node finder (filter > pin all) > List

Modifier le temps de simulation


Edit > End Time > Time

Modifier les paramètres de la simulation (funtionnal ou timming et fichier WaveForm)


Assign > Simulator setting

Si vous modifier les I/O du projet source :


Processing > Generate Node Finder File

Générer la netlist de simulation fonctionnelle


Processing > Generate simulation functional netlist

Lancer la simulation
Processing > Start Simulation

4. Programmation du composant
Tool > Programmer > Start

15

Vous aimerez peut-être aussi