INF3500
Conception et réalisation de systèmes numériques
Pierre Langlois
Département de génie informatique et génie logiciel
École Polytechnique de Montréal
Juillet 2013
Cette création est mise à disposition selon le Contrat Paternité-Pas d'Utilisation Commerciale-Partage des
Conditions Initiales à l'Identique 2.5 Canada (http://creativecommons.org/licenses/by-nc-sa/2.5/ca/), sauf
pour les images dont les sources et notices de copyright sont indiquées explicitement, et pour lesquelles
les détenteurs originaux des copyrights conservent tous leurs droits.
Table des matières
Table des matières
Chapitre 1
Introduction ........................................................................................................................... 1
1.1
Systèmes numériques et systèmes analogiques............................................................................. 1
1.2
Niveaux d’abstraction des systèmes numériques .......................................................................... 2
1.3
Implémentation des systèmes numériques .................................................................................... 2
Chapitre 2
Description de circuits numériques avec VHDL .................................................................. 5
2.1
Langages de description matérielle ............................................................................................... 5
2.2
Entités et architectures .................................................................................................................. 5
2.3
Trois styles de description du comportement d’un circuit ............................................................ 8
2.4
Modélisation d’éléments à mémoire en VHDL .......................................................................... 13
2.5
Quelques détails du langage VHDL............................................................................................ 16
2.6
Exercices ..................................................................................................................................... 24
Chapitre 3
Technologies de logique programmable ............................................................................. 27
3.1
Circuits SSI, MSI et LSI ............................................................................................................. 27
3.2
Mémoires mortes programmables : PROM, EPROM, EEPROM .............................................. 28
3.3
Réseaux logiques programmables : PLA, PAL et GAL ............................................................. 30
3.4
Circuits logiques programmables complexes (CPLD) ................................................................ 34
3.5
Réseaux pré-diffusés programmables (FPGA) ........................................................................... 35
3.6
Comparaison d’équivalences en termes de portes logiques ........................................................ 43
3.7
Technologies de programmation pour logique programmable ................................................... 43
3.8
Exercices ..................................................................................................................................... 49
Chapitre 4
Flot de conception d’un circuit numérique ......................................................................... 51
4.1
Décomposition architecturale ..................................................................................................... 51
4.2
Vue d’ensemble du flot de conception ........................................................................................ 52
4.3
Description : code HDL, schémas, diagrammes d’état, etc. ....................................................... 52
4.4
Simulation fonctionnelle d’un modèle VHDL ............................................................................ 53
4.5
Synthèse ...................................................................................................................................... 53
4.6
Implémentation ........................................................................................................................... 56
4.7
Extraction de métriques et annotation des délais ........................................................................ 57
INF3500 : Conception et réalisation de systèmes numériques
i
v. 2.5, juillet 2013
Table des matières
4.8
Génération du fichier de configuration et programmation .......................................................... 58
4.9
Exercices ..................................................................................................................................... 59
Chapitre 5
Conception de chemins des données ................................................................................... 61
5.1
Les processeurs ........................................................................................................................... 61
5.2
Approche RTL : principes et notation......................................................................................... 62
5.3
Modules combinatoires utilisés dans les chemins des données .................................................. 64
5.4
Éléments à mémoire pour chemins des données ......................................................................... 69
5.5
Unités fonctionnelles .................................................................................................................. 76
5.6
Exercices ..................................................................................................................................... 81
Chapitre 6
Conception d’unités de contrôle ......................................................................................... 83
6.1
Circuits séquentiels ..................................................................................................................... 83
6.2
Analyse d’un circuit séquentiel synchrone ................................................................................. 84
6.3
Description de machines à états en VHDL ................................................................................. 85
6.4
Conception de machines à états .................................................................................................. 91
6.5
Retour sur la conception de processeurs et l’approche RTL....................................................... 95
6.6
Exemple de processeur à usage spécifique: multiplicateur série ................................................ 96
6.7
Exemple : joueur de blackjack .................................................................................................. 101
6.8
Exercices ................................................................................................................................... 106
Chapitre 7
Vérification de circuits numériques .................................................................................. 109
7.1
Concepts fondamentaux ............................................................................................................ 109
7.2
Banc d’essai de base et clause after...................................................................................... 110
7.3
Simulation d’un modèle VHDL ................................................................................................ 111
7.4
Vecteurs de test encodés dans un tableau de constantes ........................................................... 112
7.5
Génération algorithmique de vecteurs de test ........................................................................... 113
7.6
Observation et évaluation des réponses : assertions ................................................................. 115
7.7
Entrées et sorties par fichiers .................................................................................................... 118
7.8
Utilisation de configurations en VHDL.......................................................................... 121
7.9
Instanciation directe d’une entité .............................................................................................. 121
7.10
Vérification d’un circuit séquentiel synchrone par banc d’essai............................................... 122
INF3500 : Conception et réalisation de systèmes numériques
ii
v. 2.5, juillet 2013
Table des matières
7.11
Élaboration d’un plan de test .................................................................................................... 124
7.12
Composition d’un ensemble de vecteurs de test ....................................................................... 126
7.13
Concepts avancés de vérification .............................................................................................. 130
7.14
Exercices ................................................................................................................................... 131
Chapitre 8
Considérations pratiques ................................................................................................... 133
8.1
Introduction ............................................................................................................................... 133
8.2
Paramètres de synchronisation .................................................................................................. 133
8.3
Fréquence maximale d’opération et chemin critique ................................................................ 135
8.4
Le déphasage d’horloge ............................................................................................................ 136
8.5
Synchronisation entre domaines d’horloge différents............................................................... 137
8.6
Optimisation d’un design pour la surface ou le débit ............................................................... 137
8.7
Génération de signaux d’horloge .............................................................................................. 142
8.8
Conception et implémentation pour FPGA ............................................................................... 144
8.9
Documentation de systèmes numériques .................................................................................. 145
8.10
Quelques principes importants en conception numérique ........................................................ 146
8.11
Exercices ................................................................................................................................... 147
Chapitre 9
Conception et réalisation de processeurs à usage général ................................................. 149
9.1
Introduction ............................................................................................................................... 149
9.2
Chemin des données d’un processeur à usage général.............................................................. 150
9.3
L’unité de contrôle .................................................................................................................... 157
9.4
Exemple de programme ............................................................................................................ 163
9.5
Accélération d’un processeur .................................................................................................... 163
9.6
Exercices ................................................................................................................................... 164
Chapitre 10
Annexe : Revue des systèmes numériques........................................................................ 167
10.1
Variables booléennes ................................................................................................................ 167
10.2
Fonctions booléennes, symboles et tables de vérité .................................................................. 167
10.3
Algèbre booléenne .................................................................................................................... 169
10.4
Formes canoniques et expansion en mintermes et maxtermes .................................................. 169
10.5
Simplification d’expressions booléennes à l’aide de tables de Karnaugh ................................ 170
INF3500 : Conception et réalisation de systèmes numériques
iii
v. 2.5, juillet 2013
Table des matières
10.6
Autres fonctions logiques.......................................................................................................... 172
10.7
Délais et chronogrammes .......................................................................................................... 173
10.8
Codes numériques et alphanumériques ..................................................................................... 174
10.9
Éléments à mémoire de base ..................................................................................................... 176
Bibliographie............................................................................................................................................. 181
INF3500 : Conception et réalisation de systèmes numériques
iv
v. 2.5, juillet 2013
Chapitre 1
1.1
Introduction
Systèmes numériques et systèmes analogiques
Par « numérique », on veut dire « discret ».
Par « analogique » on veut dire « continu ».
Les systèmes numériques nous entourent. Quelques exemples de systèmes numériques dans la vie de tous
les jours sont : les téléphones intelligents, les baladeurs, les caméras numériques, les ordinateurs, les calculatrices et les montres électroniques.
Un système numérique traite de l’information sous forme discrète, c'est-à-dire qui peut prendre un
nombre fini de valeurs ou d’états différents. Cependant, les systèmes numériques doivent souvent traiter
de l’information venant de leur environnement. Dans la plupart des cas, cette information est analogique à
la base, c'est-à-dire qu’elle est continue en grandeur et qu’elle peut varier de façon continue dans le temps
et dans l’espace.
Voici quelques exemples de phénomènes continus :

la voix, la musique, les impulsions d’un sonar et autres sons, qui sont en fait des variations de pression dans un matériel solide, liquide ou gazeux;

les signaux électriques provenant du cerveau ou du cœur;

les phénomènes naturels : la température de l’air, la pression atmosphérique, la vitesse et la direction
du vent, le débit d’une rivière;

la position et l’attitude d’un corps dans l’espace;

les images et les vidéos; et,

les signaux de communication et de radar (signaux en radiofréquences).
Voici quelques exemples de phénomènes discrets :

le nombre de personnes dans une salle;

le solde d’un compte bancaire;

un arbre généalogique; et,

l’ensemble des cours d’un programme universitaire.
En général, on convertit les signaux de nature non-électrique en signaux électriques, et vice-versa, à l’aide
d’un transducteur comme un microphone, un haut-parleur, une caméra numérique, un écran d’ordinateur,
une antenne, un thermomètre électronique, un indicateur de débit ou un accéléromètre. Ensuite, on mesure
l’intensité électrique correspondant au phénomène ou à la quantité physique pour en indiquer la valeur à
un moment précis. Finalement, on convertit cette intensité électrique en un nombre pouvant être traité par
le système numérique. Ce processus s’appelle la numérisation d’un signal.
Le traitement effectué sur l’information numérisée peut inclure :

la compression d’une image;

la reconnaissance ou la synthèse de la parole;

la transmission d’information dans un réseau; et,

la confirmation de l’identité d’une personne selon des caractéristiques biométriques.
On retrouve ces applications dans la vie de tous les jours.
INF3500 : Conception et réalisation de systèmes numériques
1
v. 2.42, décembre 2009
Chapitre 1: Introduction
Depuis 1945 environ, les systèmes numériques ont progressivement remplacé la plupart des systèmes
analogiques, pour les raisons suivantes :

la fiabilité accrue due à l’indépendance aux variations de température, de tension d’alimentation et de
temps;

la possibilité de transmettre et reproduire l’information de façon exacte;

la flexibilité de conception et la facilité de fabrication;

la baisse des coûts et de la taille, et l’augmentation de la fréquence d’opération.
Niveaux d’abstraction des systèmes numériques
1.2
On peut identifier trois niveaux d’abstraction pour les systèmes numériques :

le niveau système: microprocesseur, mémoire, unités d’entrée-sortie, bus;

le niveau des portes logiques: les portes de base (ET, OU, NON, etc.), les circuits combinatoires
(multiplexeurs, encodeurs, additionneurs, multiplicateurs, etc.), et les éléments à mémoire (bascules et
loquets); et,

le niveau des circuits: transistors, diodes, résistances, condensateurs et inductances.
Le cours INF3500 concerne principalement le niveau des portes logiques et, dans une moindre mesure,
celui du système.
1.3
Implémentation des systèmes numériques
1.3.1
Considérations d’implémentation
Il y a quatre considérations fondamentales pour l’implémentation d’un système numérique. Leurs importances relatives dépendent grandement de l’application visée, alors elles sont présentées ici en ordre alphabétique :

La précision des calculs: La précision requise pour les calculs effectués est dictée par la bande dynamique des signaux à traiter. Par exemple, en téléphonie, la voix est numérisée avec 8 bits, donnant
256 niveaux possibles. Sur un CD audio, cependant, les sons sont numérisés avec 16 bits, donnant
65536 niveaux. La musique sur un CD audio est donc représentée avec une précision en amplitude
256 fois plus grande que la voix sur une ligne téléphonique.

La puissance consommée: Pour une application où le système doit être alimenté par piles, un critère
fondamental de performance est sa durée d’opération. Pour d’autres applications, la dissipation de la
chaleur est un problème aussi important. En effet, l’augmentation de la puissance consommée couplée
à la réduction de la taille des dispositifs a pour effet de compliquer significativement la gestion thermique des circuits.

La taille du système: La miniaturisation des systèmes numériques est un aspect important ayant mené
à leur adaptation à une foule d’applications. De plus, la possibilité d’intégrer un nombre croissant de
transistors sur une seule puce a pour effet de réduire le nombre de composantes d’un système et donc
d’en augmenter la fiabilité.

Le taux de traitement (la « vitesse »): Le taux de traitement réfère au nombre d’opérations pouvant
être effectuées par unité de temps. Ce taux est directement proportionnel à la fréquence d’horloge du
système et au nombre d’unités de traitement pouvant opérer en parallèle. La latence de réponse et les
débits de communication des différentes parties d’un système ont aussi un grand impact sur le taux de
traitement.
INF3500 : Conception et réalisation de systèmes numériques
2
v. 2.5, juillet 2013
Chapitre 1: Introduction
Il y a bien sûr plusieurs autres considérations en rapport avec le développement, la fabrication, le déploiement et la maintenance du système. On peut entre autres identifier la flexibilité, la lisibilité et la possibilité de réutilisation du système, sa testabilité, son temps de conception et les coûts de développement.
1.3.2
Partitionnement matériel et logiciel
Étant donné un problème à résoudre avec un système numérique, l’ingénieur doit effectuer un premier
partitionnement entre les composantes matérielles et logicielles du système.
À un extrême, une solution toute logicielle consiste à utiliser un microprocesseur et à écrire du logiciel
pour effectuer le traitement désiré. Cette solution a l’avantage de bénéficier d’une très grande flexibilité.
En effet, tout changement dans le traitement à faire peut être implémenté par une « simple » modification
du code. De plus, on peut concevoir et faire fabriquer la partie matérielle du système très tôt et travailler
sur le logiciel pendant son développement.
À l’autre extrême, une solution toute matérielle est bâtie de portes logiques et de bascules sans aucun
logiciel. Tout changement à la fonctionnalité risque alors de nécessiter un changement au matériel, avec
des répercussions importantes sur la fabrication et la mise en marché du produit. Il risque aussi d’être
beaucoup plus difficile, voir impossible, de faire des mises à jour.
La plupart des systèmes numériques se situent entre ces deux extrêmes. Les systèmes embarqués comportent en général un processeur sur lequel s’exécute du logiciel et quelques processeurs ou
coprocesseurs dédiés à des tâches particulières.
Dans le cours INF3500, on se concentrera sur les solutions principalement matérielles.
1.3.3
Options pour les solutions matérielles
Pour une solution matérielle, on utilise souvent l’acronyme ASIC : Application Specific Integrated Circuit, ou circuit intégré à application spécifique, par opposition à un circuit intégré à application générale.
Un ASIC est en général conçu sur mesure pour répondre à un besoin précis dans un produit. On veut que
le circuit soit particulièrement efficace en termes de puissance, taille ou taux de traitement. Par exemple,
un manufacturier de téléphones cellulaires peut faire concevoir un ASIC pour intégrer plusieurs des fonctions du téléphone de façon à avoir un gain de performance.
Voici quelques exemples de circuits intégrés qui ne sont pas considérés des ASICs:

microprocesseurs et processeurs DSP;

mémoires DRAM et SRAM;

composantes logiques discrètes dans un boîtier: portes logiques, multiplexeurs, etc.;

circuits à usage spécifique, comme un décodeur vidéo ou un circuit UART, mais qui sont vendus à
très grande échelle - on parle alors plutôt de ASSP: Application-Specific Standard Product.
Avec la progression de l'intégration de plus en plus de transistors sur une même puce, ces définitions et
les distinctions entre elles deviennent moins claires avec le temps. Par exemple, on peut facilement concevoir un ASIC qui comporte plusieurs microprocesseurs et de la mémoire. On parle d’un système sur
puce (SoC – System on Chip).
Il y a deux grandes classes d’ASIC : la logique fixe et la logique programmable. Elles sont décrites au
Tableau 1-1.
Un système implémenté en logique fixe ne peut être modifié. Par contre, en logique programmable, il est
possible de changer la fonction du système à faible coût et sans avoir à recourir à des processus complexes.
INF3500 : Conception et réalisation de systèmes numériques
3
v. 2.5, juillet 2013
Chapitre 1: Introduction
Dans un ASIC sur mesure, chaque porte logique peut être l’objet d’une optimisation particulière. On peut
placer et dimensionner les transistors de façon individuelle. Dans un ASIC à cellules normalisées, une
librairie de cellules est conçue ou achetée, et le système est composé en assemblant ces cellules sur un
grillage. Les cellules ont toutes la même hauteur, ce qui facilite leur disposition côte à côte. Dans un réseau prédiffusé de portes, les transistors sont disposés d’avance et il ne reste qu’à effectuer les connexions
métalliques entre eux.
Les différentes technologies de logique programmable font l’objet du Chapitre 3.
La logique fixe offre les meilleures performances à tous les points de vue. La logique programmable,
quant à elle, offre une très grande flexibilité et des coûts initiaux de développement beaucoup plus faibles.
En conséquence, la logique fixe n’est considérée que pour les applications nécessitant les plus hauts niveaux de performance et pour les cas ou les investissements initiaux peuvent être amortis sur un très
grand volume de production. De plus, les FPGAs présentement sur le marché offrent des niveaux de performance qui rencontrent ou excèdent les besoins de beaucoup d’applications.
Dans le cours INF3500, on considère principalement la logique programmable, et les FPGAs en particulier.
Technologies de circuits intégrés à application spécifique (ASIC)
Logique fixe

ASIC sur mesure
Full-custom ASIC

ASIC à cellules normalisées
Cell-based ASIC

réseau pré-diffusé de portes
Gate Array
Logique programmable

mémoire morte
Programmable Read Only Memory – PROM
Electrically Programmable ROM – EPROM
Erasable EPROM – EEPROM

réseau de logique programmable
Programmable Logic Array - PLA

circuit PAL
Programmable Array Logic™ - PAL

circuit GAL
Generic Array Logic™ - GAL

circuit logique programmable complexe
Complex Programmable Logic Device – CPLD

réseau prédiffusé programmable par l’utilisateur
Field-Programmable Gate Array – FPGA
Tableau 1-1 – technologies de circuits intégrés
INF3500 : Conception et réalisation de systèmes numériques
4
v. 2.5, juillet 2013
Chapitre 2
Description de circuits numériques avec VHDL
Ce chapitre décrit les principes de base de l’utilisation du langage VHDL pour la description de circuits
numériques combinatoires et séquentiels.
2.1
Langages de description matérielle
La description d’un circuit logique avec un schéma est limitée aux circuits les plus simples. Il est difficile
de dessiner un circuit complexe avec un schéma de portes logiques. Il est encore plus difficile de le modifier. Parfois, un simple changement dans une équation booléenne du circuit se répercute par une grande
quantité de connexions à corriger. De plus, il est difficile, voire impossible, d’utiliser des variables en
guise de paramètres d’un circuit représenté par un schéma. Pour ces raisons, les langages de description
matérielle (Hardware Description Language – HDL) ont vu le jour au début des années 1980 lorsque la
complexité des circuits à concevoir a rendu impossible l’utilisation exclusive de schémas.
Les avantages des HDL par rapport aux schémas sont :

les HDL permettent de décrire des systèmes complexes complets;

les HDL favorisent la décomposition en modules paramétrables;

les HDL facilitent l’établissement de spécifications et d’interfaces clairement définies; et,

les HDL normalisent l’échange d’informations entre plusieurs groupes travaillant sur un même projet.
Les HDL peuvent servir à trois choses :

la modélisation de circuits (surtout numériques);

la description de circuits en vue de leur synthèse (i.e. leur réalisation matérielle); et,

la documentation de circuits.
Les deux HDL de loin les plus populaires sont Verilog et VHDL. Ces deux langages jouissent de popularités semblables, et sont supportés également par la plupart des outils de conception. Verilog ressemble un
peu à C, et VHDL ressemble à ADA. Les deux langages sont relativement faciles à apprendre, mais difficiles à maîtriser. VHDL est plus vaste, bien que plusieurs des particularités pour lesquelles Verilog n’a
pas d’équivalent soient rarement utilisées. Quand on connaît l’un des deux langages, il est relativement
aisé de passer à l’autre. Un troisième langage, SystemC, gagne en popularité. Dans le présent document,
on ne considère que VHDL.
L’acronyme VHDL signifie Very High Speed Integrated Circuit (VHSIC) Hardware Description Language (HDL). VHDL est un langage de programmation complet. Le langage a été développé pour le
compte du gouvernement américain pour documenter la conception d’ASIC. Il est fortement inspiré du
langage ADA. Rapidement, des simulateurs de VHDL sont apparus, puis des synthétiseurs capables de
traduire un programme VHDL en une liste d’interconnexions entre des portes logiques (netlist) pouvant
être réalisée sur un ASIC.
Le langage VHDL est normalisé par l’IEEE. La première norme remonte à 1987. Des mises à jour ont eu
lieu en 1993, 2000, 2002 et 2008. Le présent document se base sur la norme 1076-2002 puisque la norme
1076-2008 n’a été publiée qu’en janvier 2009. La norme plus récente est mal supportée par les outils de
conception au moment de la préparation du présent document.
2.2
Entités et architectures
On peut décrire un circuit combinatoire en VHDL en exprimant la fonction booléenne réalisée directement, tel que montré dans l’Exemple 2-1.
INF3500 : Conception et réalisation de systèmes numériques
5
v. 2.42, décembre 2009
Chapitre 2 : Description de circuits numériques avec VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity add3bits is
port (
Cin : in std_logic;
X : in std_logic;
Y : in std_logic;
Cout : out std_logic;
S : out std_logic
);
end add3bits;
Cin
X
S
T1
T3
Y
architecture flotDeDonnees of add3bits is
signal T1 : std_logic;
signal T2 : std_logic;
signal T3 : std_logic;
begin
S <= T1 xor Cin;
Cout <= T3 or T2;
T1 <= X xor Y;
T2 <= X and Y;
T3 <= Cin and T1;
end flotDeDonnees;
T2
Cout
Exemple 2-1 – circuit combinatoire décrit en VHDL
Les énoncés library et use indiquent qu’on doit importer tous les éléments déclarés et définis dans le
package normalisé std_logic_1164, compilé dans la libraire IEEE. Dans l’exemple, cette librairie
est requise pour le type std_logic qui est communément utilisé pour les signaux et les ports d’un circuit.
2.2.1
Déclaration d’un module : l’entité
Le bloc entity définit le nom d’un module ainsi que son interface avec le monde extérieur. Le format
du bloc entity est montré dans l’Exemple 2-2. La définition d’une entité est analogue à la définition
d’une classe en programmation orientée-objet. Une fois une entité déclarée, on peut l’instancier autant de
fois que nécessaire.
entity nom-de-l-entité is
generic (
paramètre1 : type := valeur-par-défaut;
paramètre2 : type := valeur-par-défaut;
…
);
port (
port1 : direction type;
port2 : direction type;
…
);
end nom-de-l-entité;
Exemple 2-2 – format du bloc entity
L’énoncé generic permet de passer des paramètres à chaque instance de l’entité. L’énoncé port définit l’interface entre le monde extérieur et l’entité. Il énumère les ports du circuit, leur direction, ainsi que
leur type. Pour la description de systèmes numériques, les trois directions les plus populaires sont :
INF3500 : Conception et réalisation de systèmes numériques
6
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL

in pour les ports d’entrée;

out pour les ports de sortie; et,

inout pour les ports bidirectionnels.
2.2.2
Définition du comportement d’un module : l’architecture
Le bloc architecture définit le comportement d’une entité, c'est-à-dire son fonctionnement intérieur.
Chaque architecture porte un identificateur et est reliée à une seule entité. Cependant, une entité peut
avoir plusieurs architectures. Au moment de la simulation du circuit ou de sa synthèse en matériel, une
seule architecture doit être identifiée pour chaque entité. Le format du bloc architecture est montré
dans l’Exemple 2-3.
Le bloc architecture comporte deux parties : une partie déclarative et un corps. Dans la partie déclarative, on peut retrouver des déclarations de signaux, de constantes, de composantes et de types. On peut
aussi y définir des sous-routines sous la forme de fonctions et de procédures. Dans le corps de
l’architecture on retrouve des énoncés concurrents qui décrivent le comportement de l’entité à laquelle l’architecture est rattachée.
architecture nom-de-l-architecture of nom-de-l-entité is
[déclarations de signaux, constantes, composantes, types]
begin
[énoncés concurrents]
end nom-de-l-architecture;
Exemple 2-3 – format simplifié du bloc architecture
Dans l’Exemple 2-1 la partie déclarative de l’architecture contient la déclaration de trois objets de
catégorie signal. Ces signaux correspondent à des fils du circuit. Un signal doit avoir un identificateur
et un type. Dans l’Exemple 2-1, les types des trois signaux sont std_logic. Ce type peut prendre suffisamment des valeurs nécessaires pour représenter adéquatement un signal électrique réel d’un circuit
numérique. Comme une architecture est associée à une entité, toutes les déclarations faites à l’intérieur du
bloc entité sont visibles dans l’architecture, incluant les ports. En fait, les ports de l’entité sont traités
comme des objets de type signal à l’intérieur d’une architecture.
Dans l’Exemple 2-1 le corps de l’architecture débute avec l’énoncé begin. Il contient cinq énoncés
d’assignation de valeur aux signaux et aux ports de sortie de la paire entité/architecture. Les énoncés sont
exprimés sous la forme d’équations booléennes, avec des mots clés représentatifs. Le symbole ‘<=’ signifie ici une assignation de valeur et non une comparaison de grandeur.
À l’intérieur d’une architecture, les énoncés d’assignation de valeur à des signaux sont réputés être
exécutés de façon concurrente. En fait, chaque énoncé est évalué dès qu’un changement de valeur est
détecté dans l’expression à la droite du symbole d’assignation. L’ordre dans lequel les énoncés sont écrits
dans le fichier source est sans importance. Cette distinction par rapport aux langages de programmation
plus populaires comme C et Java est fondamentale. Ce principe est illustré dans l’Exemple 2-1 en plaçant
le circuit logique à côté de son modèle en VHDL. Tout comme dans le schéma, les cinq énoncés
d’assignation de valeur représentent des actions simultanées. L’ordre dans lequel ils sont présentés dans la
description est sans importance. Seuls les ports, les composantes du circuit et les points de connexions
entre eux ont une influence sur le comportement du circuit.
INF3500 : Conception et réalisation de systèmes numériques
7
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
Trois styles de description du comportement d’un circuit
2.3
Le corps d’une architecture contient des énoncés qui sont réputés être exécutés de façon concurrente. Les
trois sortes d’énoncés concurrents les plus utilisés pour la description d’un circuit sont :

les assignations de signaux concurrentes, choisies et conditionnelles;

les instanciations de composantes; et,

les processus.
Chaque sorte d’énoncé concurrent correspond à un style de description de circuit, montrés au Tableau
2-1. Les trois styles ont chacun des avantages et des inconvénients, et sont décrits dans les sections suivantes.
Énoncés concurrents
Style de description du circuit
Assignations de signaux concurrentes, choisies et conditionnelles
Par flot de données
Instanciations de composantes
Structurale
Processus
Comportementale
Tableau 2-1 – énoncés concurrents et styles de description
2.3.1
Description par flot de données
Le modèle d’un circuit numérique par flot de données décrit sa fonction sans nécessairement définir sa
structure. En général, cela signifie que les valeurs des signaux et ports du circuit sont établies par des
assignation concurrentes de valeurs (concurrent signal assignment).
Pour les circuits combinatoires, les assignations concurrentes à des signaux utilisent souvent des opérateurs logiques qui sont des mots clés du langage: and, or, nand, nor, xor, xnor, not. On peut
utiliser des parenthèses pour faire respecter la préséance requise dans les expressions. Ceci est illustré
dans l’Exemple 2-4.
library ieee;
use ieee.std_logic_1164.all;
entity combinatoire1 is
port (
A : in std_logic;
B : in std_logic;
C : in std_logic;
F : out std_logic
);
end combinatoire1;
A
F
B
C
architecture flotDeDonnees1 of combinatoire1 is
begin
F <= not(A and (B xor not(C)));
end flotDeDonnees1;
Exemple 2-4 – description par flot de données
Il est possible de choisir la valeur à assigner à un signal parmi une liste de valeurs possibles d’une expression. Ce type d’assignation s’appelle une assignation choisie (selected signal assignment). L’Exemple 2-5
illustre ce type d’assignation. Une deuxième architecture est définie pour l’entité combinatoire1 de
l’Exemple 2-4. Cette fois, au lieu d’utiliser une fonction booléenne, on définit le fonctionnement du circuit avec l’équivalent d’une table de vérité. L’énoncé with-select permet d’assigner une valeur à un
INF3500 : Conception et réalisation de systèmes numériques
8
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
signal selon différentes valeurs d’une expression de sélection. Les différents choix doivent être mutuellement exclusifs. L’énoncé peut inclure une clause others pour ‘attraper’ toutes les combinaisons non
énumérées. L’énoncé with-select est similaire aux énoncés switch et case des langages de programmation de haut niveau.
architecture flotDeDonnees2 of combinatoire1 is
signal entree : std_logic_vector(2 downto 0);
begin
entree <= (A, B, C);
with entree select
F <=
'1' when "000",
'1' when "001",
'1' when "010",
'1' when "011",
'0' when "100",
'1' when "101",
'1' when "110",
'0' when "111",
'0' when others;
end flotDeDonnees2;
A
0
0
0
0
1
1
1
1
B
0
0
1
1
0
0
1
1
C
0
1
0
1
0
1
0
1
F
1
1
1
1
0
1
1
0
Exemple 2-5 – assignation choisie
Dans l’Exemple 2-5, on définit un signal temporaire entree, de type std_logic_vector, combinant trois signaux de type std_logic. On assigne à entree la concaténation des ports A, B et C.
L’ordre est important pour l’évaluation des différentes conditions de l’énoncé with-select. Ce signal
combiné sert ensuite à choisir une valeur à assigner au port F. La clause others est requise parce que le
type std_logic peut prendre d’autres valeurs que ‘0’ et ‘1’.
Il est aussi possible de choisir la valeur à assigner à un signal selon qu’une condition soit vraie ou non. Ce
type d’assignation s’appelle une assignation conditionnelle (conditionnal signal assignment), et est illustré par l’Exemple 2-6. Une troisième architecture est définie pour l’entité combinatoire1 de
l’Exemple 2-4. Cette fois, on utilise l’énoncé when-else, qui est similaire à l’énoncé if-thenelse. Dans l’Exemple 2-6, on assigne la valeur ‘1’ au signal F si la condition entre parenthèses est vraie.
Sinon, on lui assigne la valeur ‘0’. On se rappelle que la porte ou-exclusif produit une sortie vraie quand
ses entrées sont différentes.
Le lecteur pourra vérifier que les circuits logiques de l’Exemple 2-4 et de l’Exemple 2-6 sont équivalents
à la table de vérité de l’Exemple 2-5.
architecture flotDeDonnees3 of combinatoire1 is
begin
F <= '1' when (A = '0' or B /= C) else '0';
end flotDeDonnees3;
A
F
B
C
Exemple 2-6 – assignation conditionnelle
L’énoncé when-else nécessite une expression à valeur booléenne. En plus des opérateurs logiques
comme and et xnor, une expression à valeur booléenne peut inclure les opérateurs relationnels =, /=, <,
<=, >, >=. On remarque que l’opérateur relationnel d’égalité est un symbole unique ‘=’, et que le symbole ‘<=’ a un double usage en VHDL : pour signifier « plus petit ou égal » et « assignation concurrente à
un signal ». Le contexte détermine la bonne façon d’interpréter l’opérateur.
INF3500 : Conception et réalisation de systèmes numériques
9
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
2.3.2
Description structurale
Un circuit numérique peut être défini par sa structure, c'est-à-dire par un assemblage de blocs. Une description structurale correspond à une description par schéma, où les instanciations de composantes et leurs
interconnexions sont énumérées avec du texte. Une description structurale est appropriée pour relier entre
eux différents sous-systèmes d’un système numérique. En général, il est préférable d’utiliser un éditeur de
schéma pour décrire un tel circuit, et laisser un outil générer automatiquement le code VHDL structural.
Une description structurale nécessite la déclaration, avec le mot clé component, de chacune des composantes utilisées. Cette déclaration est faite dans la région déclarative d’une architecture. Ensuite, on
peut instancier chaque composante déclarée autant de fois que nécessaire. On déclare en général des fils
avec des objets signal, et on établit les connexions par des assignations concurrentes.
L’Exemple 2-7 illustre la description structurale de l’entité combinatoire1 de l’Exemple 2-4. On
suppose dans cet exemple que les composantes INV, NAND2 et XOR2 sont des entités déclarées dans
d’autres fichiers, et pour lesquelles il existe des descriptions de leur comportement à l’aide
d’architectures. Ces fichiers doivent avoir été compilés dans une librairie qui est visible lors de la compilation du code de l’Exemple 2-7.
L’instanciation d’une composante doit inclure une étiquette (U1, U2 et U3 dans l’exemple). Elle est suivie
de l’identificateur de la composante, et de la liste des connexions à ses ports d’entrée et de sortie.
L’assignation des connexions aux ports des composantes peut être faite par position, c'est-à-dire dans le
même ordre que pour la déclaration de la composante. Elles peuvent aussi être faites explicitement en
spécifiant les noms des ports de la composante et les noms des signaux qui y sont connectés, tel que montré dans l’Exemple 2-7.
architecture structurale of combinatoire1 is
component INV -- inverseur
port (I : in std_logic; O : out std_logic);
end component;
component NAND2
port (I0, I1 : in std_logic; O : out std_logic);
end component;
component XOR2
port (I0 : in std_logic; I1 : in std_logic; O : out std_logic);
end component;
signal NET18 : std_logic;
signal NET37 : std_logic;
begin
U1 : NAND2 port map(I0 => NET37, I1 => A, O => F);
U2 : XOR2 port map(I0 => NET18, I1 => B, O => NET37);
U3 : INV port map(I => C, O => NET18);
end architecture structurale;
Exemple 2-7 – description structurale
L’instanciation d’une composante est un énoncé concurrent. Cela signifie que sa position dans le fichier
est sans importance. Les connexions pour toutes les instanciations de composantes et toutes les assignations concurrentes à des signaux sont réputées se produire simultanément.
INF3500 : Conception et réalisation de systèmes numériques
10
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
2.3.3
Description comportementale
En VHDL, la description comportementale d’un système numérique est faite à l’aide d’énoncés similaires
à ceux d’un langage procédural comme C et Java, incluant les structures de condition et de répétition. La
possibilité d’utiliser une description comportementale est un outil très puissant aux concepteurs de circuits numériques. En effet, il est alors possible d’abstraire le comportement du circuit à un très haut niveau, et donc de définir un système complexe en peu de temps, de façon concise, paramétrable et
facilement modifiable. Cependant, comme une description comportementale peut prendre multiples
formes, il faut garder en tête la nature du circuit désiré et l’inventaire de composantes matérielles disponibles pour s’assurer que la description puisse être synthétisée en un circuit de complexité acceptable.
Les descriptions comportementales en VHDL se font à l’aide de l’énoncé process (pour processus) à
l’intérieur d’une architecture. Un processus décrit une partie du circuit qui s’exécute de façon concurrente à d’autres processus et à des assignations concurrentes de signaux. La forme d’un énoncé
process est illustrée dans l’Exemple 2-8.
[étiquette] : process (liste de sensitivité)
[déclarations de constantes et de variables]
begin
énoncés exéctués séquentiellement;
end process;
Exemple 2-8 – forme de l’énoncé process
L’énoncé process comporte deux parties : une partie déclarative et un corps. Dans la partie déclarative,
on peut retrouver des déclarations de types, d’objets des catégories variable et constant, de fonctions et de procédure. Les items déclarés dans cette partie ne sont visibles qu’à l’intérieur du processus.
Le corps de l’énoncé process suit l’énoncé begin. On y retrouve des énoncés séquentiels qui décrivent le comportement du processus.
La liste de sensitivité du processus permet d’établir quand celui-ci doit être exécuté. Lors de la simulation,
un processus est exécuté une première fois quand la simulation est lancée. Ensuite, il n’est exécuté que
lorsqu’au moins un des signaux de sa liste de sensitivité est modifié. Il est possible qu’un processus assigne une valeur à un signal qui est présent dans sa liste de sensitivité. Dans ce cas, le processus est lancé
à nouveau dès qu’il se termine.
Un énoncé d’assignation concurrente est interprété en VHDL comme une forme abrégée d’un processus.
Ce principe est illustré par l’Exemple 2-9 qui donne deux versions équivalentes pour l’assignation d’une
valeur à un signal. Dans la version avec processus, on remarque que les trois signaux qui doivent être
évalués pour déterminer la valeur à assigner au signal F sont placés dans la liste de sensitivité du processus. Dans le cas montré ici, la partie déclarative du processus est vide.
-- utilisation d’un processus
process (A, B, C)
begin
F <= not(A and (B xor not(C)));
end process;
-- assignation concurrente
F <= not(A and (B xor not(C)));
Exemple 2-9 – équivalence d’une assignation concurrente et d’un énoncé process
Dans le corps du processus, les énoncés sont évalués de façon séquentielle, contrairement aux énoncés
dans le corps de l’architecture qui sont évalués de façon concurrente. Cependant, les assignations de valeurs aux objets de catégorie signal ne sont effectuées que lorsque le processus se termine. Si plusieurs
assignations sont faites à un objet de catégorie signal dans un processus, seule la dernière sera en fait
INF3500 : Conception et réalisation de systèmes numériques
11
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
effectuée. Les expressions contenant des objets de catégorie signal sont évaluées avec les valeurs présentes lorsque le processus est lancé. Il faut donc utiliser les assignations multiples et interdépendantes
d’objets de catégorie signal à l’intérieur d’un processus avec beaucoup de prudence.
Contrairement aux objets de catégorie signal, les objets de catégorie variable prennent immédiatement la valeur qui leur est assignée par un énoncé. Cela signifie que leur comportement est identique à
celui des variables d’un programme dans un langage comme C ou Java. En VHDL, les variables sont
utilisées à l’intérieur des processus pour garder des valeurs de façon temporaire, pour calculer des valeurs
devant être utilisées dans des expressions subséquentes, ou encore pour séparer de longs calculs sur plusieurs énoncés.
Pour assigner une valeur à un objet de la catégorie variable, on utilise le symbole ‘:=’. Le symbole
‘<=’ est réservé aux objets de la catégorie signal.
À l’intérieur d’un processus, on peut utiliser des structures de condition (if-then-else et case) et de
répétition (loop), et on peut appeler des fonctions et des procédures.
Pour illustrer l’utilisation d’un processus en VHDL, considérons la description d’une porte ET à quatre
entrées. Dans le code de l’Exemple 2-10, deux architectures sont présentées. La première correspond à un
flot de données et la deuxième à une description comportementale.
library ieee;
use ieee.std_logic_1164.all;
entity porteET4 is
port (
I : in std_logic_vector(3 downto 0);
F : out std_logic
);
end porteET4;
architecture flotDeDonnees of porteET4 is
begin
F <= I(3) and I(2) and I(1) and I(0);
end flotDeDonnees;
architecture comportementale of porteET4 is
begin
process (I)
variable sortie : std_logic;
begin
sortie := '1';
for k in 3 downto 0 loop
sortie := sortie and I(k);
end loop;
F <= sortie;
end process;
end comportementale;
Exemple 2-10 – deux façons de décrire une porte ET à quatre entrées
Dans la description par flot de données, la fonction ET est appliquée aux quatre ports d’entrée par une
équation booléenne. Dans la version comportementale, on effectue l’opération bit par bit à l’aide d’une
boucle. Cette approche a l’avantage d’être beaucoup plus flexible, parce qu’alors on n’est plus restreint à
un nombre fixe d’entrées. Ceci est montré dans l’Exemple 2-11.
INF3500 : Conception et réalisation de systèmes numériques
12
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
L’énoncé generic du bloc entity est utilisé comme paramètre de l’entité pour indiquer le nombre
d’entrées de la porte ET. Ce paramètre sert à définir la largeur du port d’entrée et à déterminer les bornes
de la boucle du procédé pour effectuer les opérations logiques sur chacune des W entrées. La valeur de W
peut être spécifiée lors de l’instanciation de l’entité, et la valeur 8 est donnée par défaut si aucune valeur
n’est spécifiée. Il serait impossible de décrire une porte ET avec un nombre d’entrées variable par un flot
de données.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity porteET is
generic (
W : positive := 8 -- le nombre d'entrées de la porte ET
);
port (
I : in std_logic_vector(W - 1 downto 0);
F : out std_logic
);
end porteET;
architecture comportementale of porteET is
begin
process (I)
variable sortie : std_logic;
begin
sortie := '1';
for k in W - 1 downto 0 loop
sortie := sortie and I(k);
end loop;
F <= sortie;
end process;
end comportementale;
Exemple 2-11 – une porte ET à nombre d’entrées variable
Il est important d’observer que, bien que la boucle à l’intérieur du processus s’exécute W fois quand au
moins un des bits du port I change, ces exécutions sont réputées prendre un temps infinitésimalement
court. La boucle n’est ici qu’une manière compacte de décrire une opération logique entre un nombre
variable d’opérandes. Comme la variable de boucle k prend des valeurs statiques au moment de
l’exécution du code, on peut « dérouler » la boucle avant de l’interpréter.
2.4
Modélisation d’éléments à mémoire en VHDL
2.4.1
Bascule D
La bascule D (D flip-flop) est le type d’élément à mémoire de loin le plus commun. Elle a deux entrées :
un signal de données D et une horloge CLK (clock). L’entrée D est saisie sur une transition de l’horloge et
est gardée en mémoire jusqu’à la prochaine transition d’horloge. La sortie Q donne la valeur mémorisée.
Pour modéliser une bascule, il est nécessaire de pouvoir décrire le fait que le changement d’état se produit
sur une transition d’un signal d’horloge et non sur sa valeur. Pour ce faire, on peut utiliser les attributs
d’événement (event attribute) définis en VHDL. L’Exemple 2-12 démontre l’utilisation de l’attribut
event sur le signal CLK, dénoté par CLK’event. Cet attribut est vrai quand un changement de valeur
se produit sur le signal auquel il est associé. Pour distinguer entre un front montant et un front descendant,
on doit de plus spécifier la valeur du signal immédiatement après que l’événement ait eu lieu, soit ‘1’
pour un front montant et ‘0’ pour un front descendant.
INF3500 : Conception et réalisation de systèmes numériques
13
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
library ieee;
use ieee.std_logic_1164.all;
entity basculeD is
port (
CLK : in STD_LOGIC;
D : in STD_LOGIC;
Q : out STD_LOGIC
);
end basculeD;
-- horloge
-- entrée
-- sortie
D
architecture basculeD of basculeD is
begin
process(CLK) is
begin
if (CLK = '1' and CLK'event) then
Q <= D;
end if;
end process;
end basculeD;
Q
CLK
Q'
Exemple 2-12 – bascule D
Le package std_logic_1164 contient aussi deux fonctions qui combinent ces conditions,
rising_edge() et falling_edge(). Ces deux fonctions retournent des valeurs booléennes. Le
Tableau 2-2 résume les options possibles.
Comportement désiré
option 1
option 2
front montant
front descendant
CLK’event and CLK = ‘1’
CLK’event and CLK = ‘0’
rising_edge(CLK)
falling_edge(CLK)
Tableau 2-2 – spécifier un front d’horloge pour une bascule D
2.4.2
Bascule D avec signal d’initialisation
Tous les circuits séquentiels doivent pouvoir être placés dans un état de départ connu. Il est donc essentiel
de pouvoir initialiser les éléments à mémoire du circuit à l’aide d’un signal spécial.
Il y a deux possibilités pour le signal d’initialisation. On peut vouloir :

un comportement asynchrone; ou,

un comportement synchrone.
Une initialisation asynchrone se fait indépendamment du signal d’horloge, alors qu’une initialisation synchrone se produit lors du prochain front actif du signal de contrôle.
La modélisation en VHDL de ces différents comportements se fait par l’utilisation judicieuse d’énoncés
if-else. L’Exemple 2-13 présente une entité avec deux architectures. Pour l’architecture
basculeDRasynch, l’énoncé d’initialisation est placé avant la condition qui détecte un front
d’horloge. Cette description correspond donc à une initialisation asynchrone. Une initialisation synchrone
est démontrée dans l’architecture basculeDRsynch. L’énoncé d’initialisation est alors placé à
l’intérieur de la condition détectant un front d’horloge.
INF3500 : Conception et réalisation de systèmes numériques
14
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
library IEEE;
use IEEE.std_logic_1164.all;
entity basculeDR is
port (
reset : in STD_LOGIC;
CLK : in STD_LOGIC;
D : in STD_LOGIC;
Q : out STD_LOGIC
);
end basculeDR;
-----
signal de remise à zéro
signal d'horloge
entrée
sortie
architecture basculeDRasynch of basculeDR is
begin
process(CLK, reset) is
begin
if (reset = '0') then
Q <= '0';
elsif (rising_edge(CLK)) then
Q <= D;
end if;
end process;
end basculeDRasynch;
architecture basculeDRsynch of basculeDR is
begin
process(CLK, reset) is
begin
if (rising_edge(CLK)) then
if (reset = '0') then
Q <= '0';
else
Q <= D;
end if;
end if;
end process;
end basculeDRsynch;
Exemple 2-13 – bascule D avec initialisation asynchrone ou synchrone
2.4.3
Loquet D
Le loquet D (Dlatch) est le type de loquet le plus commun. Il a deux entrées : un signal de données D et
un signal de contrôle G (Gate). Il a deux modes de fonctionnement: transparent et mémoire, déterminés
par la valeur de G (1 et 0 respectivement). Dans le mode transparent, la sortie Q a la même valeur que
l’entrée D. Dans le mode mémoire, la sortie Q conserve sa valeur.
Un loquet D peut-être modélisé en VHDL par un énoncé if-then à l’intérieur d’un processus, tel que
montré à l’Exemple 2-14. Dans l’Exemple 2-14, un processus a dans sa liste de sensitivité le signal de
contrôle G et le signal de donnée D. Le signal D est assigné à la sortie Q quand le signal de contrôle G est
actif. Cette situation correspond au mode ‘transparent’ du loquet. Si le signal de contrôle G n’est pas actif,
alors aucun changement ne doit être apporté au signal de sortie Q. Le loquet est alors en mode ‘mémoire’.
Ce comportement correspond bien à un loquet D.
Une simple modification permet de choisir la valeur ‘0’ comme valeur active pour le signal G, si désiré.
INF3500 : Conception et réalisation de systèmes numériques
15
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
library ieee;
use ieee.std_logic_1164.all;
entity loquetD is
port (
G : in STD_LOGIC;
-- contrôle
D : in STD_LOGIC;
-- donnée
Q : out STD_LOGIC
);
end loquetD;
architecture loquetD of loquetD is
begin
process(G, D) is
begin
if (G = '1') then
Q <= D;
-else
-- implicite, infère élément à mémoire
--- ne pas changer Q
end if;
end process;
end loquetD;
Exemple 2-14 – loquet D
2.5
Quelques détails du langage VHDL
2.5.1
Espaces, littéraux et commentaires
Il n’y a pas de différence entre les espaces, tabulations et retours de chariot, présents seuls ou en groupe.
Le langage n’est pas sensible à la casse.
Un littéral composé d’un caractère unique est placé entre apostrophes : ‘a’, ‘5’.
Un littéral composé d’une chaîne de caractères est placé entre guillemets : "bonjour", "123ABC".
Un littéral numérique peut être spécifié avec sa base, avec le format suivant :
base#chiffres[.chiffres]#[exposant]
où les crochets indiquent des éléments facultatifs. La base doit être entre 2 et 16, inclusivement. Par
exemple, les nombres suivants ont tous la même valeur : 10#33# = 10#3.3#E1 = 2#10001# = 16#21# =
7#45#. Les chiffres doivent être inférieurs à la base, et peuvent prendre les valeurs 0 à F inclusivement.
Un littéral composé de bits peut être exprimé en bases 2, 8 ou 16, avec les spécificateurs de base B, O et
X, respectivement : B"11111111", O"377", X"FF".
Tout texte placé après deux tirets et jusqu’à la fin d’une ligne est un commentaire, ce qui est semblable au
‘//’ de C. Il n’y a pas de commentaires en bloc (/* … */) en VHDL.
2.5.2
Objets
Ici, ‘objet’ n’a pas le même sens que dans un langage orienté objet.
Il y a quatre catégories d’objets en VHDL :

constant (et generic) : peut contenir une valeur unique qui ne change pas; un objet generic
est une constante spéciale permettant d’appliquer un paramètre à une entité lors de son instanciation;
INF3500 : Conception et réalisation de systèmes numériques
16
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL

variable: peut contenir une valeur temporaire; les objets variable sont utiles pour stocker des
valeurs intérimaires dans les calculs;

signal (et port) : peut contenir une liste de valeurs dans le temps; un objet signal correspond
en général à un fil d’un circuit; un port d’une entité est implicitement un signal pour cette entité;

file: un objet dans lequel on peut écrire et lire des valeurs, et qui correspond à un fichier du système d’exploitation.
Lors de la déclaration d’un objet, on spécifie sa catégorie, son identificateur et son type. On peut aussi lui
assigner une valeur initiale.
2.5.3
Identificateurs
Un identificateur de base légal est composé de lettres, chiffres et/ou du soulignement. Le premier caractère doit être une lettre, le dernier ne peut pas être le soulignement, et on ne peut utiliser deux soulignements de suite. Un identificateur ne peut pas être l’un des mots réservés du langage.
Les mots réservés de VHDL (selon la norme 1076-2002) sont :
abs, access, after, alias, all, and, architecture, array, assert, attribute, begin,
block, body, buffer, bus, case, component, configuration, constant, disconnect,
downto, else, elsif, end, entity, exit, file, for, function, generate, generic, group,
guarded, if, impure, in, inertial, inout, is, label, library, linkage, literal, loop,
map, mod, nand, new, next, nor, not, null, of, on, open, or, others, out, package,
port, postponed, procedural, procedure, process, protected, pure, range, record,
reference, register, reject, rem, report, return, rol, ror, select, severity, signal,
shared, sla, sll, sra, srl, subtype, then, to, transport, type, unaffected, units,
until, use, variable, wait, when, while, with, xnor, xor
2.5.4
Types prédéfinis
VHDL a peu de types prédéfinis. Les types prédéfinis le sont dans le package standard, qui est inclut
implicitement dans tous les cas. Cependant, VHDL permet de définir de nouveaux types ainsi que des
sous-types. Un sous-type est identique à un type, sauf que les valeurs permises de l’objet sont restreintes à
un sous-ensemble de celles du type duquel il est dérivé.
Avec le temps, certains types non prédéfinis ont été adoptés par l’industrie, et mêmes normalisés par
l’IEEE. Par exemple, le package std_logic_1164 définit des types essentiels en VHDL, bien qu’ils
ne fassent pas partie du langage de base.
Il y a quatre catégories principales de types en VHDL : scalaires, composés, pointeurs et fichiers. Les
types les plus utilisés pour la description de systèmes numériques sont résumés au Tableau 2-3.
Un objet de type std_logic peut prendre l’une des 9 valeurs définies dans le tableau. Ces valeurs permettent de modéliser la plupart des conditions qu’on pourrait retrouver sur un fil dans un circuit numérique.
2.5.5
Conversions explicites de type et qualification de type
VHDL est un langage fortement typé, dans le sens où les assignations de valeurs, les opérateurs et les
paramètres de fonctions et de procédure doivent être des types correspondant. Il est possible de faire des
conversions explicites de types (type casting).
Les conversions explicites de type ne sont permises qu’entre type apparentés, comme par exemple real
et integer. Elles sont aussi permises entre les types de tableaux qui ont les mêmes dimensions, pour
lesquels les types d’indice sont apparentés et pour lesquels les éléments sont du même type.
INF3500 : Conception et réalisation de systèmes numériques
17
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
Une conversion explicite de type est faite en spécifiant le type désiré immédiatement suivi d’une expression à convertir placée entre parenthèses, tel que démontré dans l’Exemple 2-15.
catégorie
scalaires
type
ou sous-type
boolean
source
de la définition
type prédéfini
FALSE et TRUE
bit
type prédéfini
‘0’ et ‘1’
character
type prédéfini
256 caractères de la norme ISO 8859-1,
avec des abréviations reconnues et certaines qui sont propres à VHDL
Les 128 premiers sont les caractères
ASCII.
integer
type prédéfini
plage minimale de –231 + 1 à 231 – 1
natural
sous-type prédéfini
0 à 231 – 1
positive
sous-type prédéfini
1 à 231 – 1
real
type prédéfini
typiquement
–1.7014111E±308 à 1.7014111E±308
std_logic
Package
std_logic_1164
‘U’ : valeur inconnue, pas initialisée
‘X’ : valeur inconnue forcée
‘0’ : 0 forcé
‘1’ : 1 forcé
‘Z’ : haute impédance (pas connecté)
‘W’ : inconnu faible
‘L’ : 0 faible
‘H’ : 1 faible
‘-‘ : peu importe (don’t care)
bit_vector
type prédéfini
tableau de bit
string
type prédéfini
tableau de character
std_logic_vector
Package
std_logic_1164
tableau de std_logic
unsigned
Package
numeric_std
tableau de std_logic, interprété
comme un nombre binaire non signé
signed
Package
numeric_std
tableau de std_logic, interprété
comme un nombre binaire signé
en complément à deux
composés
valeurs
Tableau 2-3 - types les plus communément utilisés pour la synthèse de circuits numériques
INF3500 : Conception et réalisation de systèmes numériques
18
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
variable v1 : real;
variable v2 : integer;
variable v3 : std_logic_vector(3 downto 0) := "1101";
v1
v2
---
:=
:=
v2
v3
real(3);
integer(1.5 * 0.999);
:= integer("0010"); -- illégal
:= std_logic_vector(5); -- illégal
Exemple 2-15 – conversions explicites de types
La qualification d’une expression est parfois nécessaire pour spécifier le type d’une expression. Cette
opération est presqu’uniquement utilisée pour qualifier des littéraux. Par exemple, le littéral ‘1’ peut être
de type character ou std_logic selon le Tableau 2-3.
La qualification d’une expression est effectuée en utilisant le type désiré, suivi d’une apostrophe et de
l’expression à qualifier entre parenthèses :

character’(‘1’)

std_logic’(‘1’)
La qualification d’une expression est surtout utilisée pour déterminer le type de littéraux et éliminer
l’ambigüité lors d’un appel d’une fonction polymorphique.
2.5.6
Définition de nouveaux types
On peut définir de nouveaux types avec le mot clé type, et des sous-types avec le mot clé subtype.
On peut entre autres définir des types composés dont les éléments sont tous du même type et sont numérotés (vecteurs ou matrices – array) ou dont les éléments peuvent être de types différents et qui sont
nommés (structures – record). L’Exemple 2-16 illustre la définition de nouveaux types dont des types
composés.
type entiers_sous_20 is range 0 to 19;
type matrice_reelle_1_par_10 is array (1 to 10) of real;
type tableauSLV3 is array (natural range <>) of std_logic_vector(2 downto 0);
constant vecteurs : tableauSLV3 :=
("000", "001", "010", "011", "100", "101", "110", "111");
type nom_de_mois is (janvier, février, mars, avril, mai, juin, juillet, aout,
septembre, octobre, novembre, décembre);
type date is record
jour : integer range 1 to 31;
mois : nom_de_mois;
année : positive range 1 to 3000;
end record;
constant confederation : date := (1, juillet, 1867);
Exemple 2-16 – définition de nouveaux types
Pour les vecteurs et matrices, la déclaration du type doit inclure les indices et le type des éléments. On
accède à un élément particulier à l’aide de son indice placé entre parenthèses.
INF3500 : Conception et réalisation de systèmes numériques
19
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
Pour les structures, la déclaration du type doit inclure, pour chaque élément, son nom et son type. On
accède à un élément en particulier à l’aide de son nom précédé d’un point.
2.5.7
Opérateurs
Les opérateurs prédéfinis de VHDL sont décrits au Tableau 2-4.
VHDL permet la surcharge des opérateurs. Les packages communément utilisés redéfinissent la plupart
des opérateurs pour les types présentés au Tableau 2-3, ce qui élargit grandement les possibilités
d’utilisation par rapport aux conditions définies dans le Tableau 2-4.
type de
l’opérande
de gauche
catégorie
opérateurs
logique
and, or, nand, nor,
xor, xnor, not
relation
=, /=, <, <=, >, >=
décalage
sll (déc. logique gauche),
srl (déc. logique droite),
sla (déc. arithmétique gauche),
sra (déc. arithmétique droit),
rol (rotation gauche),
ror (rotation droite)
arithmétique
+, -, *, /,
abs (valeur absolue),
mod (modulo),
rem (reste)
type de
type de
l’opérande l’expression
de droite
bit, boolean
scalaire ou tableau
tableau de
bit ou
boolean
type
numérique
type
numérique
comme
l’opérande
de gauche
type
numérique
integer
** (exponentiation)
concaténation
integer
boolean
&
tableau ou type énuméré
tableau
Tableau 2-4 – opérateurs prédéfinis en VHDL
2.5.8
Structures de répétition et de sélection
On peut utiliser deux types de structures de répétition à l’intérieur d’un processus : for et while, montrées à l’Exemple 2-17. Pour la boucle for, il n’est pas nécessaire de déclarer le compteur de boucle. La
déclaration du compteur et son type sont implicitement déclarés par la gamme de valeurs de la boucle.
for identificateur in gammeDeValeurs loop
énoncés;
end loop;
while ( condition de répétition ) loop
énoncés;
end loop;
Exemple 2-17 – structures de répétition
INF3500 : Conception et réalisation de systèmes numériques
20
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
À l’intérieur d’une boucle, on peut utiliser l’énoncé next qui interrompt le flot de la boucle et passe à
l’itération suivante, et l’énoncé exit qui termine la boucle complètement.
On peut utiliser deux types de structures de sélection à l’intérieur d’un processus : if-then-else et
case, montrés à l’Exemple 2-18.
-- énoncé if-then-else
if ( condition ) then
énoncés;
elsif ( condition ) then
énoncés;
else
énoncés;
end if;
-- énoncé case
case ( expression ) is
when ( choix unique, plusieurs séparés par ‘|’, ou gamme de valeurs ) =>
énoncés;
when ( choix unique, plusieurs séparés par ‘|’, ou gamme de valeurs ) =>
énoncés;
when others =>
énoncés;
end case;
Exemple 2-18 – structures de sélection
2.5.9
Sous-programmes : fonctions et procédures
Il y a deux types de sous-programmes en VHDL, les fonctions et les procédures.
Une fonction est un sous-programme qui retourne un résultat unique. La valeur retournée peut être d’un
type scalaire ou composé. Une fonction peut accepter des paramètres en entrée. Ces paramètres ne peuvent pas être modifiés par la fonction. On utilise un appel de fonction dans une expression.
L’Exemple 2-19 démontre une fonction qui calcule la fonction logique ET sur les éléments d’un objet de
type STD_LOGIC_VECTOR, comme l’entité de l’Exemple 2-11.
function porteET(V: std_logic_vector) return std_logic is
variable resultat : std_logic := '1';
begin
for k in V'range loop
resultat := resultat and V(k);
end loop;
return resultat;
end;
Exemple 2-19 – définition d’une fonction
Une procédure est un sous-programme avec une liste de paramètres. Comme pour les ports d’une entité,
les paramètres peuvent avoir les modes in, out et inout, permettant ainsi à la procédure d’accepter des
valeurs en entrée, de retourner des résultats, et de modifier des paramètres qui lui sont passés. Alors qu’un
appel de fonction est utilisé dans une expression, un appel de procédure est considéré comme un énoncé
concurrent.
Les fonctions et les procédures peuvent être surchargées, c'est-à-dire que deux peuvent avoir le même
identificateur mais une liste de paramètres différents.
INF3500 : Conception et réalisation de systèmes numériques
21
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
Les opérateurs de VHDL peuvent aussi être surchargés en utilisant le nom de l’opérateur comme identificateur du sous-programme, placé entre guillemets.
2.5.10 Package
En VHDL, un package est un fichier contenant des déclarations pouvant être utilisés dans d’autres fichiers. Un package contient deux parties : une déclaration et un corps. En général, on utilise un package
pour regrouper des définitions de types, des déclarations de constantes et des déclarations et des définitions de fonctions et procédures. Les définitions de sous-programmes doivent être placées dans le corps
du package.
L’Exemple 2-20 est un extrait du package normalisé numeric_std de la librairie IEEE. Dans la déclaration du package, l’exemple illustre deux définitions de types et une déclaration d’une fonction. Le package complet contient les déclarations de plus d’une centaine de fonctions. Dans le corps du package, on
retrouve la définition de toutes les fonctions déclarées précédemment, ainsi que la définition d’autres
fonctions utilisées uniquement à l’interne dans le package.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
package NUMERIC_STD is
type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;
type SIGNED is array (NATURAL range <>) of STD_LOGIC;
function "abs" (ARG: SIGNED) return SIGNED;
-- autres declarations ...
end NUMERIC_STD;
package body NUMERIC_STD is
function "abs" (ARG: SIGNED) return SIGNED is
constant ARG_LEFT: INTEGER := ARG'LENGTH-1;
alias XARG: SIGNED(ARG_LEFT downto 0) is ARG;
variable RESULT: SIGNED(ARG_LEFT downto 0);
begin
if ARG'LENGTH < 1 then return NAS;
end if;
RESULT := TO_01(XARG, 'X');
if (RESULT(RESULT'LEFT)='X') then return RESULT;
end if;
if RESULT(RESULT'LEFT) = '1' then
RESULT := -RESULT;
end if;
return RESULT;
end "abs";
-- autres définitions ...
end NUMERIC_STD;
Exemple 2-20 – extrait du package numeric_std, © IEEE
INF3500 : Conception et réalisation de systèmes numériques
22
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
2.5.11 Library
En VHDL, une librairie (library) est un endroit où le compilateur entrepose l’information nécessaire
pour un design en particulier. Ainsi, un design peut être décrit par une grande quantité de fichiers distincts. On peut aussi réutiliser des composantes entre plusieurs designs. Le nom de la librairie par défaut
est work, mais les outils de design suivent souvent leur propre convention. Par exemple, avec ActiveHDL, le nom de la librairie par défaut est le même que le nom du design.
Dans une libraire, on peut retrouver cinq types d’unités de design (design units), regroupés en unités primaires et secondaires. Une unité secondaire doit être liée à une unité primaire dans une librairie. Les cinq
types d’unités de design sont montrés au Tableau 2-5.
Unité primaire
Unité secondaire associée
Entité (section 2.2.1)
Architecture (section 2.2.2)
Package : déclaration (section 2.5.10)
Package : corps (section 2.5.10)
Configuration (section 7.8)
Tableau 2-5 – cinq types d’unités dans une librairie
Pour placer le résultat de la compilation d’une unité de design dans une librairie autre que la librairie par
défaut, il faut se référer à la documentation du compilateur. Par exemple, pour Active-HDL, un outil spécial (Library Manager) sert à gérer les libraires.
Pour rendre visible le contenu d’une librairie, il faut utiliser le mot clé library puis spécifier l’unité de
design qu’on désire utiliser à l’aide du mot clé use. L’Exemple 2-21 illustre comment on rend visible
toutes les déclarations du package std_logic_1164 de la libraire IEEE dans un fichier.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
Exemple 2-21 – utilisation d’une unité de design d’une librairie
2.5.12 Attributs
En VHDL, les attributs permettent d’obtenir de l’information à propos de types, signaux, variables, constantes, etc. Par exemple, on peut définir la charge capacitive associée à un signal, ou bien les coordonnées
X et Y d’un composant dans un circuit. VHDL inclut des attributs prédéfinis, et on peut aussi en définir
de nouveaux.
Les attributs prédéfinis sont répartis en cinq classes : valeur, fonction, signal, type et gamme de valeurs.
Le Tableau 2-6 présente quelques exemples d’attributs VHDL communément utilisés.
INF3500 : Conception et réalisation de systèmes numériques
23
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
Utilisation de l’attribut
Résultat
A’left, A’right
Indice le plus à gauche, le plus à droite du vecteur A
A’low, A’high
Indice le plus bas, le plus haut du vecteur A
A’range
La gamme des indices du vecteur A
A’length
Le nombre d’éléments du vecteur A
T’left, T’right,
T’low, T’high
La valeur la plus à gauche, à droite, la plus basse, la plus
élevée du type T
T’Image(x)
La représentation textuelle de la valeur x dans le type T.
T’Value(s)
La valeur dans le type T de la chaîne de caractères s.
S’event
Vrai si un événement s’est produit sur le signal S.
Tableau 2-6 – quelques attributs VHDL prédéfinis communément utilisés
2.6
Exercices
1. Consultez une référence de VHDL et comparez l’assignation de signal choisie (with-select) avec
l’énoncé case.
2. Une porte universelle peut réaliser toutes les fonctions booléennes possibles de ses entrées.
a. Combien de fonctions une porte universelle à deux entrées peut-elle réaliser?
b. Donner un module VHDL pour une porte universelle à deux entrées.
3. Décrire un module en VHDL pour un décodeur d’affichage à sept segments pour les 16 chiffres en
base hexadécimale.
4. Décrire un module en VHDL qui accepte en entrée un nombre de six bits et qui a deux sorties, une
pour indiquer si le nombre est divisible par trois et l’autre s’il est divisible par cinq.
5. La fonction majorité est vraie quand le nombre de bits en entrée de valeur ‘1’ est plus grand que le
nombre de bits de valeur ‘0’.
a. Donner un module VHDL pour une fonction majorité à 4 bits.
b. Donner un module VHDL pour une fonction majorité à nombre arbitraire de bits.
6. La fonction parité est vraie si le nombre de bits en entrée égal à ‘1’ est pair.
a. Donner un module VHDL pour une fonction parité à 4 bits.
INF3500 : Conception et réalisation de systèmes numériques
24
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
b. Donner un module VHDL pour une fonction parité à nombre arbitraire de bits.
7. Décrire un module en VHDL qui accepte en entrée un code BCD et qui a une sortie indiquant si le
code est valide ou non.
8. Décrire un module en VHDL qui accepte en entrée deux nombres A et B exprimés en complément à
deux avec quatre bits, et avec deux sorties : une indiquant si les nombres sont identiques, et l’autre
indiquant si A est plus grand que B.
9. Faites la simulation du code suivant. Quelle valeur prend le port F? Pourquoi?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity exempleSignaux is
port (F : out std_logic);
end exempleSignaux;
architecture arch1 of exempleSignaux is
begin
F <= '1';
F <= '0';
end arch1;
10. Faites la simulation du code suivant. Quelle valeur prend le port F si A = ‘1’? Pourquoi? Quel est
l’effet d’inverser les deux énoncés à l’intérieur du processus?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity exempleSignaux is
port (A : in std_logic; F : out std_logic);
end exempleSignaux;
architecture arch2 of exempleSignaux is
begin
process(A)
begin
F <= A;
F <= not(A);
end process;
end arch2;
11. Modélisez un loquet S-R en VHDL conforme à la description de la section 10.9.1 et vérifiez son fonctionnement à l’aide d’un simulateur. Modifiez votre modèle si nécessaire pour que les entrées interdites résultent en des sorties de valeur ‘X’ du type std_logic. Simulez votre module pour toutes
les combinaisons d’entrée possibles.
12. Modélisez, en VHDL, un loquet D ayant un signal d’initialisation à ‘0’ ou à ‘1’, spécifié par un énoncé generic dans la partie déclarative de l’entité. Simulez votre modèle pour toutes les combinaisons d’entrées et de transitions possibles.
13. Reproduisez le circuit de la Figure 10-7 en VHDL et vérifiez à l’aide d’un simulateur que le fonctionnement correspond bien à celui d’une bascule.
INF3500 : Conception et réalisation de systèmes numériques
25
v. 2.5, juillet 2013
Chapitre 2 : Description de circuits numériques avec VHDL
INF3500 : Conception et réalisation de systèmes numériques
26
v. 2.5, juillet 2013
Chapitre 3
Technologies de logique programmable
À la section 1.3, on a discuté de considérations pour l’implémentation matérielle de circuits numériques.
On a parlé de ce qui affecte l’implémentation d’un circuit, du problème du partitionnement logicielmatériel et des options pour les solutions matérielles. Dans ce chapitre, on voit ces options plus en détail.
3.1
Circuits SSI, MSI et LSI
Les premiers circuits numériques intégrés sont apparus sur le marché dans les années 1960. On les classifiait alors selon le nombre de transistors qu’ils intégraient. Les trois acronymes de base, SSI, MSI et LSI,
référaient respectivement à Small, Medium et Large Scale Integration. Un circuit SSI contenait de l’ordre
de 102 transistors, un circuit MSI de l’ordre de 103, et un circuit LSI de l’ordre de 104 transistors.
Une famille de circuits SSI/MSI très populaire jusqu’au début des années 1990 était la série 7400. Normalisés dans l’industrie, ils étaient manufacturés par plusieurs fournisseurs. Les deux derniers chiffres reflétaient la fonction logique réalisée et la position des signaux sur les pattes de la puce. Quelques exemples
sont indiqués au Tableau 3-1, et une puce 7400 est illustrée à la Figure 3-1 avec son schéma interne.
numéro
fonction
7400
4 × NON-ET
7402
4 × NON-OU
7404
8 × NON
7411
3 × ET (3 entrées)
7473
2 × bascule JK avec reset
Tableau 3-1 – exemples de la famille 7400
Figure 3-1 – puce 7400 (source : Wikipédia)
INF3500 : Conception et réalisation de systèmes numériques
27
v. 2.42, décembre 2009
Chapitre 3 : Technologies de logique programmable
Les circuits MSI incluaient entre autres des multiplexeurs, décodeurs, registres et compteurs. Miraculeusement (pour l’époque), leur coût de fabrication n’était pas significativement supérieur à celui des composantes SSI à cause de l’amélioration continue des processus de fabrication.
Les circuits LSI incluaient entre autres des mémoires, des processeurs simples et les premiers microprocesseurs comme le 4004 d’Intel à plus de 2000 transistors.
À la fin des années 1970 et au début des années 1980, on a vu apparaître les circuits VLSI (pour Very
Large Scale Integration) avec 105 transistors. L’acronyme ULSI (pour Ultra) a été peu utilisé, VLSI se
généralisant pour tous les circuits intégrés très complexes.
On utilise encore parfois aujourd’hui les puces SSI-LSI si le circuit à implémenter est très simple, comme
par exemple pour mener une sortie sur une planchette intégrant des composantes plus sophistiquées mais
ne partageant pas de signal commun. Un désavantage de cette approche est que cette partie du circuit ne
peut plus être modifiée une fois fabriquée. On n’imaginerait pas aujourd’hui utiliser les puces SSI-LSI
comme technologie de base pour implémenter un système numérique.
3.2
Mémoires mortes programmables : PROM, EPROM, EEPROM
Les premiers circuits programmables par l’utilisateur étaient des mémoires mortes programmables (Programmable Read Only Memory – PROM). Une PROM ne se programmait qu’une seule fois.
Une mémoire ROM consiste en :

un décodeur avec n signaux d’entrée;

un réseau OU programmé (ou programmable une fois) avec 2n mots de m bits chacun ;

m signaux de sortie.
Le réseau programmé comporte 2n lignes de m colonnes chacune. À l’intersection de chaque ligne avec
une colonne on trouve un élément électronique à mémoire. Une fois programmée, la ROM de 2 n mots de
m bits peut générer m fonctions de n variables simultanément.
La Figure 3-2 illustre une mémoire ROM de 16 octets. L’intérêt d’utiliser une mémoire ROM pour implémenter des fonctions logiques est que la tâche est facile parce qu’il n’est pas nécessaire de tenter de
réduire les équations. L’inconvénient est que la réalisation finale n’est pas nécessairement la plus efficace.
Par exemple, la Figure 3-3 illustre comment on pourrait implémenter les équations logiques suivantes, qui
sont données en somme de mintermes et en version réduite :
F0   m(0,1,4,6)  A' B' AC '
F1   m(2,3,4,6,7)  B  AC '
F2   m(0,1,2,6)  A' B' BC '
F3   m(2,3,5,6,7)  AC  B
La Figure 3-3 montre un décodeur avec trois entrées et huit sorties. Chaque minterme des entrées A, B et
C est disponible sur une ligne horizontale (Word Lines). Quatre lignes verticales peuvent être reliées à
chacune des lignes horizontales des mintermes. Il y a quatre lignes parce que c’est une mémoire de quatre
bits seulement. Les quatre lignes verticales sont mises à zéro par défaut par l’entremise de résistances
reliées à la masse (pull-down resistors). Si une ligne verticale n’est pas reliée à aucune ligne horizontale,
sa sortie est donc zéro.
Pour relier une ligne verticale à une ligne horizontale, il faut un dispositif de programmation, montré à la
Figure 3-3 par une flèche dans une boîte. Le dispositif doit être directionnel, comme montré dans la figure, pour empêcher une ligne horizontale d’en mener une autre par l’entremise de leurs connexions resINF3500 : Conception et réalisation de systèmes numériques
28
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
pectives. On peut donc utiliser des diodes, ou, en pratique, des transistors. Effectivement, la combinaison
des lignes horizontales et verticales et des dispositifs de programmation implémente des portes OU tel
que montré à la Figure 3-2.
décodeur 4:16
A3
A2
A1
A0
m15
m14
m13
m12
m11
m10
m9
m8
m7
m6
m5
m4
m3
m2
m1
m0
D7
D6
D5
D4
D3
D2
D1
D0
Figure 3-2 – mémoire ROM 16 × 8 bits
Figure 3-3 – programmer une ROM 8 × 4 bits (source : Roth, 5e éd., fig. 9-20, © Brooks/Cole 2004)
INF3500 : Conception et réalisation de systèmes numériques
29
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
On distingue trois sortes de mémoire ROM, différenciées par leurs technologies de programmation.

PROM : Programmable Read Only Memory, programmable une seule fois;

EPROM : Erasable Programmable Read Only Memory, programmable à plusieurs reprises, et effaçable à l’aide de rayons ultraviolets (facile à reconnaître à sa petite fenêtre); et

EEPROM : Electrically Erasable Programmable Read Only Memory, programmable à plusieurs reprises, et effaçable à l’aide d’impulsions électriques.
La Figure 3-4 illustre un microcontrôleur NEC D8749 avec EPROM intégré de 2 Ko.
Figure 3-4 – microcontrôleur NEC D8749 avec mémoire EPROM intégrée (source : Wikipédia)
3.3
Réseaux logiques programmables : PLA, PAL et GAL
Un PLA (Programmable Logic Array) est similaire à une ROM, mais il ne réalise pas tous les produits de
termes comme une ROM. Un PLA à n entrées et m sorties peut réaliser m fonctions de n variables, en
autant que chacune requiert un nombre limité de produits des variables en entrée. (En pratique, c’est
presque toujours le cas). Un PLA est composé de deux réseaux programmables, ET et OU, tel que montré
à la Figure 3-5. Le réseau ET programmable est effectivement un décodeur programmable incomplet.
La Figure 3-6 illustre comment on peut utiliser un PLA à trois entrées, six termes et quatre sorties pour
implémenter les mêmes équations logiques qu’avec la ROM de la Figure 3-3. Le nombre de termes du
PLA correspond au nombre de lignes horizontales. Pour trois entrées, une ROM aurait huit lignes horizontales. Chaque ligne horizontale a une valeur par défaut de ‘1’ logique, puisqu’elle est reliée à
l’alimentation par une résistance. Les lignes de sorties (verticales) ont des valeurs par défaut de ‘0’
comme pour la ROM. Des éléments de programmation peuvent être activés entre les lignes horizontales et
verticales.
Pour le réseau programmable ET, il y a deux lignes verticales par entrées, pour les valeurs naturelles et
complémentées des entrées. Pour forcer une ligne horizontale à zéro, on place un élément de programmation entre cette ligne et l’une des deux lignes verticales d’une entrée. Par exemple, le premier terme (la
ligne horizontale du haut) correspond à la fonction logique A’B’. Si A’ et B’ sont vrais, alors les lignes
INF3500 : Conception et réalisation de systèmes numériques
30
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
verticales correspondantes auront une valeur de ‘1’, et le premier terme aussi. Dans tous les autres cas, le
premier terme aura une valeur de ‘0’.
A3
A2
A1
A0
F2
F1
F0
Figure 3-5 – PLA à 4 entrées, 6 termes et 3 sorties
Figure 3-6 – programmer un PLA à 3 entrées, 5 termes et 4 sorties
(source : Roth, 5e éd., fig. 9-25, © Brooks/Cole 2004)
Un PAL (Programmable Array Logic) est un cas particulier de PLA. Dans un PAL, seulement le réseau
ET est programmable, alors que le réseau OU est fixe. Par conséquent, aucun produit de termes ne peut
être partagé par plus d’une fonction. Chaque fonction peut donc être optimisée séparément. La Figure 3-7
illustre une partie d’un PAL. Les entrées sont à gauche de la figure et il y a une sortie unique à droite. La
sortie est menée par une porte OU dont les deux entrées proviennent de portes ET. Les entrées de ces
portes ET ont des valeurs par défaut de ‘1’ grâce aux résistances reliées à l’alimentation. Par défaut, les
entrées de portes ET sont reliées aux versions naturelles et complémentées des entrées. Pour programmer
le dispositif, il faut briser des liens montrés sur la figure par des symboles ‘S’ couchés à l’horizontale,
représentant des fusibles.
INF3500 : Conception et réalisation de systèmes numériques
31
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
Figure 3-7 – partie d’un PAL
Un PAL 16L8 est montré à la Figure 3-8. Dans la désignation « 16L8 », le « 16 » donne le nombre maximal d’entrées, le « L » indique que les sorties sont en logique inversée, et le « 8 » donne le nombre maximal de sorties.
Un GAL (Generic Array Logic), de la compagnie Lattice Semiconductors, est un dispositif programmable
et configurable pouvant émuler différents types de PAL. Les pattes de sorties peuvent inclure un registre
et un signal de rétroaction vers le réseau programmable OU, et peuvent être configurées comme des ports
d’entrée ou d’entrée et sortie. Les circuits GAL remplacent aujourd’hui effectivement les composantes
SSI-LSI.
Les ROM, PAL, PLA et GAL sont composés de deux réseaux : un réseau ET qui génère des mintermes,
et un réseau OU qui permet de combiner plusieurs mintermes. La possibilité de programmer chacun de
ces réseaux détermine de quel type de dispositif il s’agit. Le tableau suivant résume la situation.
type de dispositif
réseau ET
réseau OU
ROM
fixe
(tous les mintermes sont générés par un décodeur)
programmable
PLA
programmable
(un nombre limité de mintermes peuvent être générés)
programmable
PAL
programmable
(un nombre limité de mintermes peuvent être générés)
fixe
(un nombre limité de
mintermes peuvent être
combinés)
GAL
comme PAL
comme PAL
Tableau 3-2 – distinctions entre ROM, PAL, PLA et GAL
Les PALs, PLAs et GALs incorporent aussi des registres dans des blocs configurables associés aux pattes
de sortie. Il est donc possible d’implémenter un circuit séquentiel complet sur un seul dispositif.
INF3500 : Conception et réalisation de systèmes numériques
32
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
Figure 3-8 – PAL 16L8
INF3500 : Conception et réalisation de systèmes numériques
33
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
3.4
Circuits logiques programmables complexes (CPLD)
Les ROMs, PLAs, PALs et GALs sont parfois appelés des circuits logique programmable simples (Simple
Programmable Logic Devices – SPLD).
Les CPLD sont une extension naturelle des circuits PAL. À mesure que leur complexité grandissait, la
taille des PALs était limitée par le nombre de pattes pouvant être placées sur la puce. Un CPLD incorpore
donc plusieurs PALs ou PLAs sur une seule puce avec un réseau d’interconnexions. Le réseau permet de
relier les pattes de la puce à différents blocs internes, mais aussi à relier les blocs entre eux. Il est donc
possible de composer des fonctions logiques très complexes incluant des machines à états et de petites
mémoires. La Figure 3-9 illustre un CPLD de Xilinx.
Figure 3-9 – architecture d’un CPLD de Xilinx
(source : Roth, 5e éd., fig. 9-30, © Brooks/Cole 2004)
Le système comprend quatre blocs fonctionnels qui sont des PALs à 36 entrées et 16 sorties. Les sorties
proviennent de macro-cellules contenant un élément programmable à mémoire. Le réseau
d’interconnexions permet d’établir des connexions entre les blocs d’entrées-sorties, les blocs fonctionnels
et les macro-cellules. La Figure 3-10 montre des détails du CPLD de la Figure 3-9.
Figure 3-10 – détails d’un CPLD
(source : Roth, 5e éd., fig. 9-31, © Brooks/Cole 2004)
INF3500 : Conception et réalisation de systèmes numériques
34
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
On voit les 36 entrées en versions naturelle et complémentée qui alimentent 48 portes ET à connexions
programmables. Les 48 portes ET alimentent 16 portes OU à connexions programmables. La macrocellule permet d’activer ou non la bascule avec un signal naturel ou complémenté. La cellule de sortie
contient un tampon à trois états.
3.5
Réseaux pré-diffusés programmables (FPGA)
3.5.1
Architecture générale
Les FPGA se sont imposés sur le marché des circuits logiques depuis la fin des années 1980. Alors qu’au
début ils permettaient de remplacer quelques composantes discrètes de façon plus efficace que les PALs
et PLAs, ils concurrencent de nos jours certains microprocesseurs et microcontrôleurs en complexité et en
performance.
Un FPGA est composé à la base de :

un réseau de blocs de logique programmable (Configurable Logic Block  CLB), chaque bloc pouvant
réaliser des fonctions complexes de plusieurs variables, et comportant des éléments à mémoire;

un réseau d’interconnexions programmables entre les blocs; et,

des blocs spéciaux d’entrée et de sortie avec le monde extérieur (Input/Output Block – IOB).
La Figure 3-11 illustre un modèle de FPGA.
IOB
IOB
IOB
IOB
IOB
IOB
IOB
CLB
CLB
CLB
CLB
CLB
CLB
CLB
CLB
CLB
CLB
CLB
CLB
CLB
CLB
CLB
IOB
IOB
IOB
IOB
IOB
Figure 3-11 – modèle d’un FPGA
INF3500 : Conception et réalisation de systèmes numériques
35
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
3.5.2
Blocs de logique programmable
Les FPGAs se distinguent des CPLDs par le fait que les CLBs des FPGAs sont beaucoup plus nombreux
et plus simples que les blocs fonctionnels des CPLDs. Comme ils sont présents en grand nombre sur une
même puce (de plusieurs centaines à plusieurs milliers), ils favorisent la réalisation et l’intégration d’une
multitude de circuits indépendants, comme en retrouve dans les processeurs décrits au Chapitre 9.
Il y a deux catégories de blocs de logique programmable : ceux basés sur les multiplexeurs et ceux basés
sur les tables de conversion.
Un multiplexeur avec n signaux de contrôle peut réaliser toute fonction booléenne à n + 1 variables sans
l’ajout d’autres portes logiques. Pour ce faire, on exploite le fait qu’un multiplexeur génère effectivement
tous les mintermes des signaux de contrôle S. Il ne reste qu’à spécifier la valeur qu’on veut propager
quand un des ces mintermes est vrai. La procédure de design consiste à écrire la table de vérité de la fonction en groupant les lignes par paires. À chaque paire de lignes correspond une valeur des lignes de sélection du multiplexeur. On assigne aux lignes de données l’une de quatre valeurs : 0, 1, α ou α’, où α est la
variable d’entrée la moins significative. Par exemple, considérons la fonction logique
F ( x, y, z)  m(0,5, 6, 7) . On exprime la fonction sous la forme d’une table de vérité. On rajoute une

colonne pour indiquer à quelle entrée Di chaque minterme correspond. Finalement, on indique la valeur à
donner à chaque entrée Di en fonction de la sortie F désirée et la valeur de la variable z. Cet exemple est
montré à la Figure 3-12.
#
x
y
z
F
0
1
2
3
4
5
6
7
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
1
0
0
0
0
1
1
1
entrée Di
D0
valeur
z’
D1
0
D2
z
D3
1
z’
0
0
z
2
1
3
1
F
S0
S1
x
y
Figure 3-12 – implémentation d’une fonction logique par multiplexeur
Les CLBs basés sur les tables de conversion utilisent de petites mémoires programmables au lieu de multiplexeurs. Cette approche est similaire à l’approche par multiplexeurs, mais en supposant que les entrées
du multiplexeur ne peuvent être que des constantes. Effectivement, il faut un multiplexeur deux fois plus
gros pour réaliser la même fonction, mais le routage du circuit est plus simple. De plus, le circuit peut être
plus rapide parce que les entrées du multiplexeur sont constantes.
Les FPGAs de la compagnie Altera étaient à l’origine basés sur une approche par multiplexeurs, alors que
ceux de Xilinx utilisaient des tables de conversion. La plupart des FPGAs récents utilisent des tables de
conversion. Cela ne signifie pas que des multiplexeurs ne sont plus utilisés. Au contraire, ils sont essentiels pour router adéquatement les signaux à l’intérieur d’un CLB en choisissant différentes possibilités de
configuration.
La Figure 3-13 illustre un CLB simplifié d’un FPGA de Xilinx. Le CLB est composé de :

deux tables de conversion (Look-Up Table – LUT) programmables à 4 entrées chacune, F et G, qui
sont effectivement des mémoires de 16 bits chacune;

un multiplexeur ‘H’ et son entrée associée H1 qui permet de choisir la sortie de l’une des deux tables
de conversion;
INF3500 : Conception et réalisation de systèmes numériques
36
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable

quatre multiplexeurs dont les signaux de contrôle S0 à S3 sont programmables; et,

deux éléments à mémoire configurables en bascules ou loquets.
G4
YQ
D Q
G3
G2
Table de
conversion
G
16 X 1
S0
CLK
G!
Y
H
S1
H1
F4
XQ
D Q
F3
F2
Table de
conversion
F
16 X 1
S2
CLK
F1
X
S3
CLK
Figure 3-13 – bloc de logique programmable simplifié – Xilinx
Pour plusieurs familles de FPGA, les tables de conversion peuvent aussi être utilisées comme mémoire
distribuée par l’ajout de signaux de contrôle. Des configurations très polyvalentes permettent de varier le
nombre de mots ou leur largeur, et de supporter une mémoire à un ou deux ports de sortie. De façon similaire, les tables de conversion peuvent être utilisées comme registres à décalage.
3.5.3
Terminologie : LE, LAB, ALM, slice, CLB
Pour des raisons internes aux différents manufacturiers, plusieurs termes sont utilisés pour parler de
l’architecture interne des FPGAs.
Pour les FPGAs de la famille Cyclone, Altera utilise le terme Logic Element – LE pour une cellule de
base incluant une table de conversion, un additionneur et un registre. Un Logic Array Bloc – LAB regroupe dix LEs. Pour la famille Stratix, Altera a remplacé les LEs par des blocs plus complexes, les
Adaptive Logic Modules – ALM. Un ALM comprend deux tables de conversion, deux additionneurs et
deux registres. Pour la famille Stratix, un LAB regroupe 10 ALMs.
INF3500 : Conception et réalisation de systèmes numériques
37
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
Pour les FPGAs des familles Spartan et Virtex, Xilinx utilise le terme slice pour un module de base incluant deux tables de conversion, deux additionneurs et deux registres. Un Configurable Logic Block –
CLB regroupe deux ou quatre slices, selon la famille de FPGA.
3.5.4
Routage rapide des retenues
Les applications principales des FPGAs au début des années 1990 concernaient les télécommunications et
le traitement des signaux. Ces applications requièrent des additions rapides. C’est pourquoi les fabricants
de FPGA ont rapidement intégré des circuits spécialisés pour la génération et la propagation des retenues
lors d’additions. La présence de ces circuits dédiés élimine à toutes fins pratiques le besoin d’utiliser des
architectures spéciales comme les additionneurs à retenue choisie ou à retenue anticipée, du moins pour
les applications avec au plus 32 bits de précision.
3.5.5
Blocs de mémoire intégrée
Pendant les années 1990, alors que de plus en plus de transistors étaient disponibles pour intégration sur
des puces, les fabricants de FPGA ont commencé à intégrer des modules de plus en plus complexes au
tissu de base montré à la Figure 3-11. Les blocs de mémoire ont été parmi les premiers modules ajoutés à
cause du grand besoin en mémoire de la plupart des applications. L’avantage important à intégrer des
blocs de mémoire près de logique configurable est la réduction significative des délais de propagation et
la possibilité de créer des canaux de communication parallèle très larges. La Figure 3-14 illustre
l’intégration de blocs de mémoire sous la forme d’une colonne entre les CLBs d’un FPGA.
Columns of embedded
RAM blocks
Arrays of
programmable
logic blocks
Figure 3-14 – mémoire RAM intégrée
(source : fig. 4-10, Maxfield, © Mentor Graphics 2004)
La quantité de mémoire présente dans les blocs de RAM varie à travers les différentes familles de FPGAs,
mais on peut retrouver jusqu’à 10 Méga bits de mémoire dans les plus gros et plus récents modèles. Les
INF3500 : Conception et réalisation de systèmes numériques
38
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
blocs peuvent être utilisés indépendamment ou en groupes, offrant une versatilité rarement rencontrée
dans les systèmes numériques. De plus, les blocs de mémoire peuvent être utilisés pour implémenter des
fonctions logiques, des machines à états, des registres à décalage très larges, etc.
3.5.6
Fonctions arithmétiques avancées
La multiplication est une opération fondamentale dans les applications de traitement du signal pour lesquelles les FPGAs sont très populaires. Les fabricants de FPGAs ont donc ajouté à leurs architectures des
blocs spéciaux pour réaliser cette opération. Les multiplicateurs sont en général disposés près des blocs de
mémoire RAM pour des raisons d’efficacité de routage des signaux et de disposition des ressources du
FPGA sur une puce. La Figure 3-15 illustre un tel arrangement.
RAM blocks
Multipliers
Logic blocks
Figure 3-15 – multiplicateurs intégrés
(source : fig. 4-11, Maxfield, © Mentor Graphics 2004)
Les paramètres d’opération des multiplicateurs varient selon les familles de FPGA. Un format populaire
est un multiplicateur signé de 18 × 18 bits, ce qui est suffisant pour beaucoup d’applications de traitement
du signal (le son est encodé avec 8 bits sur une ligne de téléphone et avec 16 bits par canal pour un CD
audio). Pour les applications devant traiter des opérandes plus larges, il est possible de regrouper plusieurs
multiplicateurs. Le nombre de multiplicateurs varie, mais on en retrouve facilement des dizaines même
sur les FPGAs les plus modestes.
Une autre fonction populaire est la multiplication-accumulation (Multiply-Accumulate – MAC), qui consiste à accumuler le produit de plusieurs nombres. Cette opération est utilisée entre autres pour le calcul
du produit scalaire. Afin d’accélérer cette opération, plusieurs fabricants intègrent des blocs MAC à leurs
FPGAs. Un tel bloc est montré à la Figure 3-16.
INF3500 : Conception et réalisation de systèmes numériques
39
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
Multiplier
Adder
Accumulator
A[n:0]
xx
+
B[n:0]
Y[(2n - 1):0]
MAC
Figure 3-16 – multiplication-accumulation
(source : fig. 4-11, Maxfield, © Mentor Graphics 2004)
3.5.7
Microprocesseurs fixes
On n’arrête pas le progrès. Avec le nombre de transistors intégrables sur une puce doublant tous les 18
mois, et les besoins important en contrôle dans plusieurs applications, les fabricants de FPGA intègrent
des processeurs fixes (hard) à plusieurs familles de FPGAs. La Figure 3-17 illustre deux variations, avec
un et quatre processeurs fixes.
uP
uP
uP
uP
uP
(a) One embedded core
(b) Four embedded cores
Figure 3-17 – processeur intégré
(source : fig. 4-10, Maxfield, © Mentor Graphics 2004)
INF3500 : Conception et réalisation de systèmes numériques
40
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
Les microprocesseurs intégrés ne sont pas réalisés à l’aide de blocs de logique ou de mémoire du FPGA.
Ce sont plutôt des régions de la puce optimisées comme si le microprocesseur était réalisé par lui-même
dans un circuit intégré. En général, les manufacturiers de FPGAs achètent des processeurs populaires dans
l’industrie et déjà bien connus des consommateurs, comme par exemple l’architecture PowerPC de IBM.
En intégrant ainsi un ou plusieurs microprocesseurs à un FPGA, on obtient un tissu de calcul d’une puissance très intéressante. En effet, une application peut être divisée efficacement entre des parties matérielles et logicielles; les parties matérielles sont réalisées avec les ressources configurables du FPGA, et
les parties logicielles sont réalisées avec les microprocesseurs. Là où le parallélisme des calculs l’exige,
les blocs de logique configurable peuvent accélérer les calculs par un facteur de 10×, 100× ou plus. Là où
l’application risque d’être modifiée, ou si elle nécessite beaucoup de contrôle ou d’interface avec le
monde extérieur ou entre des modules, une solution logicielle peut être obtenue plus facilement.
Avec les microprocesseurs entourés des ressources configurables du FPGA, on peut atteindre des taux
d’échange de données très élevés. Tout d’abord, la proximité physique des dispositifs réduit les délais.
Ensuite, il est possible de mettre en place des liens de communication très larges.
3.5.8
Génération et distribution d’horloge
Un problème important lors de la conception et réalisation d’un circuit numérique concerne la génération
et la distribution du signal d’horloge. Dans une application de communications et de traitement du signal,
un même circuit peut nécessiter une dizaine d’horloges de fréquences et de phases différentes.
Pour faciliter la tâche des concepteurs, les FPGAs incluent maintenant des circuits spécialisés de génération, régulation et distribution de l’horloge. Ce type de circuit accepte en entrée une horloge externe et
génère une ou plusieurs horloges internes, tel que montré à la Figure 3-18. Les horloges internes peuvent
avoir des fréquences et des phases différentes, comme montré à la Figure 3-19 et à la Figure 3-20.
Clock signal from
outside world
Clock
Manager
etc.
Daughter clocks
used to drive
internal clock trees
or output pins
Special clock
pin and pad
Figure 3-18 – génération de signaux d’horloge à partir d’une référence externe
(source : fig. 4-16, Maxfield, © Mentor Graphics 2004)
1.0 x original clock frequency
2.0 x original clock frequency
.5 x original clock frequency
Figure 3-19 – varier la fréquence d’horloge
(source : fig. 4-19, Maxfield, © Mentor Graphics 2004)
INF3500 : Conception et réalisation de systèmes numériques
41
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
0 o Phase shifted
90 o Phase shifted
180 o Phase shifted
270 o Phase shifted
Figure 3-20 – varier la phase de l’horloge
(source : fig. 4-20, Maxfield, © Mentor Graphics 2004)
Pour distribuer l’horloge à travers la puce tout en minimisant le déphasage d’horloge, on utilise un réseau
en arbre dédié. Ce réseau est alimenté soit par une patte spéciale du FPGA à laquelle est associé un amplificateur dédié, ou bien par l’entremise de signaux internes pouvant être routés au même amplificateur. La
Figure 3-21 illustre un tel arrangement.
Clock
tree
Flip-flops
Special clock
pin and pad
Clock signal from
outside world
Figure 3-21 – arbre de distribution d’horloge
(source : fig. 4-15, Maxfield, © Mentor Graphics 2004)
3.5.9
Blocs d’entrées-sorties
Les éléments logiques à l’intérieur d’un FPGA sont forcément très importants; les interfaces avec le
monde extérieur le sont tout autant. Un problème observé assez tôt lors du développement de FPGAs de
plus en plus performants est que leur capacité de traitement excédait leur capacité à recevoir des données
et transmettre des résultats. Les FPGAs sur le marché présentement incorporent donc des blocs d’entréessorties très performants.
INF3500 : Conception et réalisation de systèmes numériques
42
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
Les blocs d’entrées-sorties doivent pouvoir supporter plusieurs normes en termes de débit d’information,
de tensions et d’impédance. Ils incorporent en général une bascule pour minimiser les délais de propagation et augmenter le taux de transmission de l’information.
Comparaison d’équivalences en termes de portes logiques
3.6
La comparaison de deux FPGAs de familles différentes est difficile à faire, et spécialement si ce sont des
FPGAs de deux manufacturiers différents. Au début de l’ère FPGA, les manufacturiers ont commencé à
publier des métriques comme des « équivalent-portes » pour indiquer combien un FPGA donné pouvait
contenir de portes logiques de base (fonction NON-OU ou NON-ET) à deux entrées. Cependant, avec la
multitude de blocs spécialisés sur un FPGA aujourd’hui, il vaut mieux comparer les métriques de ressources en termes des ressources elles-mêmes, comme le nombre de tables de conversions, de bascules,
de bits de mémoire ou de microprocesseurs embarqués.
3.7
Technologies de programmation pour logique programmable
Il existe plusieurs technologies pour les dispositifs programmables. On en couvre les grandes lignes dans
cette section.
3.7.1
Fusibles
La technologie originale utilisée pour les premiers dispositifs programmables, les mémoires ROM, étaient
des fusibles. Le dispositif inclut un fusible à chaque lien programmable, tel que montré à la Figure 3-22.
Le principe du fusible repose sur l’utilisation d’un métal conducteur qui fond et coupe le circuit lorsqu’il
est chauffé par un courant électrique. Pour programmer le dispositif, il faut appliquer une tension élevée
(typiquement 2 à 3 fois la tension nominale du dispositif) à des pattes choisies. Une fois les fusibles fondus, le circuit est programmé, comme montré à la Figure 3-23. L’inconvénient principal de cette technologie est qu’on ne peut programmer le dispositif qu’une seule fois. Les fusibles occupent aussi beaucoup
d’espace sur la puce. Cette technologie n’est plus utilisée.
Fuses
Logic 1
Fat
a
Pull-up resistors
Faf
NOT
&
Fbt
b
y = 0 (N/A)
AND
Fbf
NOT
Figure 3-22 – dispositif programmable avec fusibles
(source : fig. 2-2, Maxfield, © Mentor Graphics 2004)
INF3500 : Conception et réalisation de systèmes numériques
43
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
Logic 1
Fat
a
Pull-up resistors
NOT
&
b
y = a & !b
AND
Fbf
NOT
Figure 3-23 – dispositif programmable avec fusibles fondus
(source : fig. 2-3, Maxfield, © Mentor Graphics 2004)
3.7.2
Anti-fusibles
Les anti-fusibles fonctionnent de façon contraire à un fusible. Le dispositif non programmé ne contient
que des liens qui ne sont pas encore établis, comme montré à la Figure 3-24. Pour effectuer une connexion, il faut faire passer un courant élevé à travers l’anti-fusible pour fermer le circuit, comme montré à
la Figure 3-25.
Logic 1
Unprogrammed
antifuses
a
Pull-up resistors
NOT
&
b
y = 1 (N/A)
AND
NOT
Figure 3-24 – dispositif programmable avec anti-fusibles
(source : fig. 2-4, Maxfield, © Mentor Graphics 2004)
INF3500 : Conception et réalisation de systèmes numériques
44
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
Logic 1
Programmed
antifuses
a
Pull-up resistors
NOT
&
b
y = !a & b
AND
NOT
Figure 3-25 – dispositif programmable avec anti-fusibles établis
(source : fig. 2-5, Maxfield, © Mentor Graphics 2004)
Un anti-fusible est fabriqué en plaçant du silicium amorphe entre deux conducteurs métalliques. Le silicium amorphe conduit très mal le courant et peut être considéré comme un isolant. En lui appliquant une
tension élevée, cependant, on transforme le silicium amorphe en silicium polycristallin conducteur. Le
circuit électrique ainsi formé entre les deux conducteurs métalliques s’appelle un via. La Figure 3-26 illustre un anti-fusible avant et après sa programmation.
Amorphous silicon column
Polysilicon via
Metal
Oxide
Metal
Substrate
(a) Before programming
(b) After programming
Figure 3-26 – détails d’un anti-fusible
(source : fig. 2-6, Maxfield, © Mentor Graphics 2004)
Le grand désavantage de la technologie anti-fusible est que le dispositif n’est programmable qu’une seule
fois. Plusieurs FPGAs sur le marché présentement utilisent pourtant cette technologie. Un avantage important des anti-fusibles est leur immunité aux radiations, une caractéristique essentielle pour les applications spatiales. Alors qu’une cellule de mémoire SRAM peut être inversée par un rayonnement ionisant
comme des rayons gamma, une anti-fusible n’est pas affectée. De plus, il est beaucoup plus difficile de
rétroconcevoir une puce avec la technologie anti-fusible car même en exposant le circuit et en l’observant
au microscope, on ne peut distinguer les via des isolants. Cette caractéristique protège donc la propriété
intellectuelle placée sur la puce.
La compagnie Actel est un important manufacturier de FPGA à technologie anti-fusible.
INF3500 : Conception et réalisation de systèmes numériques
45
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
3.7.3
Connexions par l’entremise de transistors
On a vu à la section 3.2, et spécialement à la Figure 3-3, qu’il est important de pouvoir effectuer une connexion entre deux fils mais uniquement dans un sens. Conceptuellement, une diode pourrait faire l’affaire.
En pratique cependant, on utilise des transistors. La Figure 3-27 illustre un tel arrangement.
Logic 1
Fusible link
Pull-up resistor
Row
(word) line
Column
(data) line
Transistor
Logic 0
Figure 3-27 – connexion programmable à l’aide d’un transistor
(source : fig. 2-8, Maxfield, © Mentor Graphics 2004)
On désire pouvoir établir une connexion entre une ligne horizontale et verticale. La grille du transistor est
reliée à la ligne horizontale, un terminal est relié à la ligne verticale et l’autre à la masse. La ligne verticale est maintenue à une tension élevée par l’entremise d’une résistance connectée à la source
d’alimentation. En contrôlant la connexion entre le drain du transistor et la ligne verticale, on contrôle
effectivement la connexion entre les lignes verticale et horizontale.
Maintenant, même si la ligne verticale est mise à la masse, il n’y a pas de court-circuit entre
l’alimentation et la masse à cause de la résistance en place dans le circuit.
Un transistor PMOS fonctionne comme suit. Quand on applique une tension nulle à sa grille (un ‘0’), un
canal se forme sous celle-ci, permettant au courant de passer entre les deux autres terminaux. Quand on
applique une tension positive (un ‘1’), aucun canal n’est formé et les deux terminaux sont isolés électriquement.
Si le lien fusible est en place, une tension nulle sur la ligne horizontale aura pour effet de relier la ligne
verticale à la masse, sans pour autant établir une connexion physique entre les deux lignes. Si le lien n’est
pas là, la ligne verticale a toujours une tension élevée. À la Figure 3-27 on illustre le cas d’un lien fusible,
mais le principe est le même pour toutes les technologies de programmation.
3.7.4
EPROM et grilles flottantes
Les mémoires EPROM peuvent être programmées, effacées et reprogrammées plusieurs fois. Elles utilisent des transistors spéciaux avec une grille flottante. La Figure 3-28 illustre un transistor normal et un
transistor à grille flottante.
INF3500 : Conception et réalisation de systèmes numériques
46
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
En conditions normales, les deux transistors fonctionnent de façon identique et peuvent conduire le courant selon l’action de la grille de contrôle. Le transistor à grille flottante peut être désactivé en plaçant une
tension élevée entre sa grille et l’un de ses terminaux. Cette tension a pour effet d’induire un courant qui
vient charger la grille flottante. Une fois celle-ci chargée, il n’est plus possible de créer un canal sous la
grille et les deux terminaux sont effectivement isolés électriquement.
Source
terminal
Control gate
terminal
Drain
terminal
Source
terminal
Control gate
terminal
Drain
terminal
control gate
Silicon
dioxide
control gate
source
drain
Silicon
substrate
(a) Standard MOS transistor
floating gate
source
drain
(b) EPROM transistor
Figure 3-28 – transistors normaux et à grille flottante
(source : fig. 2-9, Maxfield, © Mentor Graphics 2004)
Pour effacer le dispositif, on l’expose à un rayonnement ultra-violet qui permet de dissiper la charge accumulée sur les grilles flottantes et ainsi réactiver les transistors.
Les transistors à grille flottante ont de plus l’avantage d’être beaucoup plus petits que les fusibles et antifusibles équivalents. Leurs désavantages sont le coût élevé du boîtier à fenêtre et le temps relativement
long, environ 20 minutes, pour les effacer. De plus, les technologies de fabrication récentes comportent
plusieurs niveaux d’interconnexions métalliques par-dessus les transistors, ce qui rend difficile ou impossible la propagation de rayons ultra-violets jusqu’aux grilles flottantes pour les décharger.
Il n’y a pas sur le marché présentement de FPGAs utilisant la technologie EPROM.
3.7.5
Cellules EEPROM et mémoire Flash
Les mémoires EEPROM et FLASH peuvent être programmées, effacées et reprogrammées plusieurs fois,
mais sans avoir recours aux rayons ultraviolets. La cellule reprogrammable de base comporte un transistor
NMOS avec une grille de contrôle et une grille flottante, comme pour le cas de l’EPROM. Cependant,
l’isolant autour de la grille flottante est plus mince que dans le cas d’une cellule EPROM, et la grille flottante chevauche partiellement le drain du transistor.
Dans son état normal, la grille flottante est déchargée et le transistor fonctionne normalement, c'est-à-dire
qu’une tension appliqué à la grille du transistor induit un canal et permet au courant de passer entre la
source et le drain du transistor. Pour ‘programmer’ la cellule, on place une tension élevée sur la grille de
contrôle et le drain du transistor, comme montré à la Figure 3-29. Comme un courant élevé circule dans le
canal, des électrons sont attirés par la grille de contrôle et vont s’emmagasiner sur la grille flottante. La
tension négative de la grille flottante est alors suffisante pour neutraliser toute tension normale appliquée
à la grille de contrôle, et le transistor ne conduit plus. Le transistor peut conserver cet état programmé
plusieurs années.
Pour ‘déprogrammer’ le transistor, on applique une tension élevée uniquement au drain de celui-ci,
comme montré à la Figure 3-30. La tension est suffisante pour attirer les électrons emmagasinés sur la
grille flottante, à travers de l’isolant. Le transistor fonctionne alors normalement.
INF3500 : Conception et réalisation de systèmes numériques
47
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
Figure 3-29 – programmer une cellule Flash (source : Wikipédia)
Figure 3-30 – déprogrammer une cellule Flash (source : Wikipédia)
Dans une mémoire EEPROM, on doit effacer chaque cellule une après l’autre. Dans une mémoire Flash,
on peut en effacer plusieurs à la fois, par bloc. Le processus est alors beaucoup plus rapide, d’où le nom
de la mémoire.
L’inconvénient de la technologie Flash est qu’elle est plus complexe à fabriquer que les processus les plus
avant-gardistes. Les puces Flash tendent donc à être en retard de quelques années par rapport aux technologies SRAM.
La compagnie Actel est un important manufacturier de FPGAs à technologie Flash.
3.7.6
Mémoire SRAM
L’acronyme SRAM signifie mémoire RAM statique (Static RAM). Une cellule de mémoire SRAM comporte 4 ou 6 transistors, par rapport à un seul pour une mémoire RAM dynamique (Dynamic RAM –
DRAM). Cependant, son fonctionnement est plus simple que pour une DRAM.
La technologie SRAM est de loin la plus populaire pour les FPGAs. Elle a plusieurs avantages. Il est facile de programmer et d’effacer le dispositif. Dès qu’un nouveau processus de fabrication microélectronique arrive sur le marché, les manufacturiers peuvent l’exploiter immédiatement à cause de la facilité
avec laquelle les cellules SRAM peuvent être fabriquées.
Cependant, dès que l’alimentation est coupée, la puce perd toute son information de configuration. La
technologie SRAM est de plus affectée par les radiations, donc elle n’est pas appropriée pour les applications spatiales. Ensuite, dans un système déployé, le fichier des bits de configuration doit être entreposé
dans une mémoire ROM sur la planchette. Cette mémoire peut être lue par quiconque voudrait voler la
propriété intellectuelle du design. Les manufacturiers de FPGA permettent de chiffrer le fichier et
d’entreposer la clé dans un registre spécial non volatile sur le FPGA. Malgré tous ces désavantages, la
technologie SRAM reste de loin la plus populaire pour les applications générales.
INF3500 : Conception et réalisation de systèmes numériques
48
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
3.7.7
Sommaire
Les trois technologies de programmation les plus populaires pour les FPGAs sont la mémoire SRAM, les
anti-fusibles et la mémoire FLASH. Le Tableau 3-3 résume les avantages et inconvénients de chaque
technologie.
caractéristique
SRAM
anti-fusibles
Flash
fabrication
à l’avant-garde
reprogrammable
oui
non
oui
temps de reprogrammation
1×T
-
3×T
volatile
oui – besoin d’un
fichier externe
non
non
prototypage
excellent
non
acceptable
sécurité
possible
excellente
dimension de la cellule
grande :
4 ou 6 transistors
très petite
consommation de puissance
moyenne
faible
moyenne
résistance aux radiations
non
oui
non
1 à 2 générations de retard
Tableau 3-3 – résumé des technologies de programmation pour FPGA
3.8
Exercices
1. Considérez un module qui doit réaliser les fonctions logiques suivantes :
F0   m(0,1,3,7)
F1   m(1,3,5,6,7)
F2   m(0,1,4,5)
F3   m(2,4,5,7)
a. Donnez son implémentation en utilisant uniquement des puces 7400 montrées à la Figure 3-1.
b. Donner son implémentation sur le circuit ROM de la Figure 3-2.
c. Donner l’implémentation des trois premières fonctions sur le PLA de la Figure 3-5.
d. Donner son implémentation sur le PAL de la Figure 3-8.
e. Donner son implémentation sur deux blocs configurables comme celui de la Figure 3-13.
2. Consultez des documents en ligne et comparez les slices de Xilinx au Logic Element d’Altera en
termes des ressources logiques disponibles et en complexité.
INF3500 : Conception et réalisation de systèmes numériques
49
v. 2.5, juillet 2013
Chapitre 3 : Technologies de logique programmable
3. Consultez des ressources en ligne et comparez les familles Spartan et Virtex de Xilinx.
4. Consultez des documents en ligne et faite l’inventaire de toutes les ressources disponibles sur le
FPGA utilisé dans les laboratoires de ce cours.
5. Un des problèmes importants avec les mémoires Flash est qu’elles ne peuvent supporter qu’un
nombre limité de cycles d’écriture. Quelles sont les conséquences de ce fait pour un FPGA destiné au
prototypage? Quels genres d’applications seraient moins susceptibles à ce problème?
INF3500 : Conception et réalisation de systèmes numériques
50
v. 2.5, juillet 2013
Chapitre 4
4.1
Flot de conception d’un circuit numérique
Décomposition architecturale
La conception d’un système numérique doit se baser sur une bonne compréhension des requis et des spécifications. Cette étape est cruciale et il est avantageux d’y consacrer une bonne part de l’activité de design. En effet, le coût associé à un changement suit en général une relation exponentielle avec le temps. Il
faut donc s’assurer de bien comprendre le problème et les attentes dès le départ.
La conception comme telle débute par une décomposition du système en ses modules principaux et par
une description abstraite de leur comportement. Un module peut aussi faire l’objet de décomposition en
plusieurs sous- modules. Pour déterminer la bonne granularité des modules, on peut observer trois principes :

La cohésion : chaque module ne devrait réaliser qu’une seule fonction ou des fonctions similaires;

La taille : un module ne devrait pas être trop grand ni trop petit; tous les modules du système devraient être de tailles comparables; et

Des interfaces claires : chaque module devrait avoir des interfaces claires avec les autres modules, ce
qui permet de mieux gérer la complexité du système au complet.
Par exemple, pour un téléphone cellulaire, on imagine que les blocs modules sont l’affichage et son unité
de contrôle, le clavier et son unité de contrôle, la radio et son unité de contrôle, un module réseau, un
module de traitement de la voix et un module de contrôle général des autres modules.
Le partitionnement consiste quant à lui à déterminer comment chaque module et sous-module sera implémenté, soit ‘en logiciel’ sur un processeur à usage général ou ‘en matériel’ sur un processeur spécialisé. La décision de placer un module d’un côté ou de l’autre est difficile et nécessite de faire des
compromis en termes de précision des calculs, puissance consommée, taille du système et taux de traitement (voir la section 1.3). Par exemple, pour un module de traitement de la voix, on peut choisir
d’implémenter un sous-module de contrôle en logiciel et un module de filtrage ou d’encodage sophistiqué
en matériel dans un coprocesseur associé.
Pour le reste de la discussion, on considère l’implémentation de modules ‘en matériel’.
Il est fréquent de modéliser le comportement d’un module à un niveau élevé avant d’en entreprendre une
description détaillée. On peut par exemple utiliser un langage comme C ou Python pour modéliser un
algorithme de chiffrage de données, ou un environnement complet comme Matlab pour modéliser, développer et adapter un algorithme de traitement d’image. À cette étape, il est utile de garder en tête des principes d’implémentation matérielle comme la façon de représenter des nombres. On peut par exemple
choisir de déjà modéliser le système en arithmétique à virgule fixe en utilisant des types de données appropriées pour les variables du modèle.
C’est aussi à l’étape de modélisation qu’on développe un banc d’essai et des cas de test contenant des
stimuli et des réponses attendues en vue de la vérification. Le fait de développer un modèle et son banc
d’essai confirme que les spécifications du design sont suffisamment claires et bien comprises pour mener
à bien le développement du module.
Dans le reste de ce chapitre, on discute du processus de conception d’un module implémenté en matériel
par un circuit numérique. Le flot de conception est d’abord présenté dans son ensemble, puis chacune des
étapes est décrite en détail. Le chapitre se termine par une brève discussion sur la documentation des systèmes numériques et par des recommandations pouvant aider les concepteurs dans leur tâche.
INF3500 : Conception et réalisation de systèmes numériques
51
v. 2.42, décembre 2009
Chapitre 4 : Flot de conception d’un circuit numérique
4.2
Vue d’ensemble du flot de conception
Un flot de conception est une séquence d’opérations permettant d’obtenir un circuit concret, implémenté
dans une technologie donnée, à partir de sa description. Un flot de conception typique de circuit numérique est illustré à la Figure 4-1. Ce flot est détaillé dans les sections suivantes.
vérification de la puce
annotation
des délais
vérification par simulation
code HDL
schéma
diagramme
d’états
synthèse
génération du
fichier de
configuration
implémentation
génération
de code
HDL
puce
contraintes
(temps et
espace)
Extraction statique des métriques d’implémentation
(ressources, délai, puissance)
Figure 4-1 - flot de conception d’un circuit numérique
4.3
Description : code HDL, schémas, diagrammes d’états, etc.
La description du module peut se faire par une combinaison de code HDL dans plusieurs langages, de
schémas, diagrammes d’états ou encore flots de données. Dans le premier cas, on peut utiliser un simple
éditeur de texte pour écrire la description en HDL. Dans les deux autres, un programme de traduction
génère une description en HDL à partir du schéma ou du diagramme entré dans l’outil. La Figure 4-2
illustre une description hiérarchique dont les unités fonctionnelles sont décrites de diverses façons.
Textual HDL
Graphical State Diagram
When clock rises
If (s == 0)
then y = (a & b) | c;
else y = c & !(d ^ e);
Top-level
block-level
schematic
Graphical Flowchart
Block-level schematic
Figure 4-2 – description hiérarchique
(source : fig. 5-3, Maxfield, © Mentor Graphics 2004)
INF3500 : Conception et réalisation de systèmes numériques
52
v. 2.5, juillet 2013
Chapitre 4 : Flot de conception d’un circuit numérique
Au début de l’ère microélectronique, tout le développement se faisait à l’aide de schémas. Un peu plus
tard, les schémas ont été complètement délaissés pour les HDL. On a ensuite réalisé que les schémas sont
idéaux pour regrouper ensemble des unités fonctionnelles d’une librairie, elles-mêmes décrites par schéma ou HDL. Une telle description hiérarchique présente d’importants avantages pour la gestion de la
complexité du module. Des compilateurs de schémas génèrent automatiquement une description HDL à
partir d’un schéma.
Comme il existe une équivalence directe entre un diagramme d’états et sa description en HDL, des outils
existent pour faire cette conversion automatiquement. L’outil accepte en paramètres quelques options de
la part du concepteur, comme par exemple pour choisir un style préféré de description HDL ou encore
pour spécifier si les sorties doivent passer par des registres ou non.
Simulation fonctionnelle d’un modèle VHDL
4.4
La simulation du code HDL permet au concepteur de vérifier que la description est conforme aux spécifications. Cette étape est très importante et requiert une grande proportion de l’effort de design. Un compilateur lit le code HDL et vérifie que la syntaxe du langage est respectée. Il génère une description
intermédiaire du code qui peut ensuite être exécutée par un simulateur.
Le simulateur nécessite qu’on spécifie des signaux à assigner aux ports d’entrée du circuit à simuler. On
peut ne spécifier qu’un ensemble de valeurs, mais il est souvent plus intéressant (et nécessaire) de spécifier plusieurs ensembles de valeurs à simuler. Différents outils de simulation facilitent la tâche de spécification des stimuli à appliquer en permettant de choisir des patrons prédéfinis.
Le simulateur évalue comment les signaux appliqués aux ports d’entrée se propagent dans le circuit et il
calcule la valeur des ports de sortie. Le fonctionnement interne du processus de simulation d’un modèle
VHDL est décrit en détails au Chapitre 7.
Les simulateurs affichent en général les résultats de la simulation sous la forme d’un chronogramme. Il
est possible en général d’observer les entrées et les sorties, ainsi que des signaux internes du circuit qui
est simulé. Certains simulateurs permettent aussi de voir les signaux sous la forme d’un tableau, un peu à
la manière d’une table de vérité. Les simulateurs peuvent aussi afficher des messages d’avertissement et
d’erreur à la console.
Une approche plus systématique et plus robuste de vérifier le bon fonctionnement d’un circuit numérique
par simulation consiste à utiliser un banc d’essai. Ce sujet est couvert en détails au Chapitre 7.
4.5
Synthèse
4.5.1
Description générale
La synthèse du code HDL est effectuée par un outil de synthèse, ou synthétiseur. Le synthétiseur produit
une description du circuit en termes d’éléments logiques simples. Le synthétiseur indique aussi les interconnexions entre ces composantes. Le produit du synthétiseur est communément appelé « liste des interconnexions (netlist)». Le processus de synthèse peut être décomposé et effectué en plusieurs passes. Ce
processus est très complexe sauf pour les circuits les plus simples.
Après le processus de synthèse, il est possible d’obtenir des métriques de la performance et des coûts du
circuit. Le synthétiseur peut en effet déjà estimer combien de tables de conversion, de bascules et de ports
d’entrée-sortie seront nécessaires. Il est possible que ce nombre soit réduit lors des étapes subséquentes,
comme par exemple si deux ports ont la même valeur, mais l’estimé est quand même utile.
Le synthétiseur peut aussi estimer les délais de propagation et identifier un chemin critique, et donc la
fréquence maximale d’horloge. Cet estimé est basé sur les ressources utilisées en supposant des délais de
INF3500 : Conception et réalisation de systèmes numériques
53
v. 2.5, juillet 2013
Chapitre 4 : Flot de conception d’un circuit numérique
routage typiques. Il peut y avoir une très grande variation entre cet estimé et la valeur finale après le placement et le routage, spécialement si on utilise une grande portion du dispositif.
Enfin, on peut simuler directement la liste des interconnexions produite par le synthétiseur afin de confirmer que ce que le synthétiseur a produit est toujours conforme aux spécifications.
4.5.2
Modélisation en VHDL pour la synthèse
La synthèse d’un circuit numérique consiste à obtenir une description du circuit en termes de composantes et d’interconnexions à partir de sa spécification dans un langage de description matérielle. Le produit de la synthèse est communément appelé « liste des interconnexions (netlist)». Un outil automatisé qui
effectue la synthèse est appelé « synthétiseur ». Le défi du synthétiseur est de réussir à modéliser le comportement sous-entendu par le code et d’inférer un circuit conforme à celui-ci. En retour, le défi du concepteur de circuits numériques est de décrire ses intentions d’une façon non ambigüe pour le synthétiseur.
VHDL est un langage très vaste et très puissant. Avec le temps, un sous-ensemble du langage a émergé
pour supporter spécifiquement le processus de synthèse. La norme 1076.6-2004 de l’IEEE définit ce sousensemble. La documentation accompagnant le synthétiseur utilisé est pratique pour connaître exactement
les parties du langage qui sont supportées ou non, les formulations préférées pour représenter une structure donnée, ainsi que les directives particulières supportées par le synthétiseur.
Il n’est pas possible en général de produire une modélisation en VHDL synthétisable pour un circuit
comme on l’écrirait dans un langage traditionnel comme C ou Java. Devant cet état de chose, le concepteur doit en tout temps garder en tête l’importance du style utilisé pour décrire un module. Une approche
qui fonctionne consiste à tout d’abord décomposer le circuit en blocs de base correspondant à des composantes logiques connues, puis à produire une description en fonction de ces blocs.
4.5.3
Types utilisés pour la synthèse
Lors de l’implémentation d’un module, il est en général nécessaire que ses ports soient des types
std_logic ou std_logic_vector parce qu’il est alors plus simple d’effectuer une assignation des
pattes de la puce à des fils particuliers. Pour représenter des nombres, les types préférés sont unsigned
pour une interprétation non signée et signed pour une interprétation signée en complément à deux. Ces
types sont définis dans le package numeric_std.
Pour représenter des signaux internes d’un module, on peut bien sûr utiliser les types std_logic,
std_logic_vector, unsigned et signed. Pour ces types, les outils de synthèse peuvent facilement faire le lien entre le modèle et sa représentation physique. De plus, la simulation du modèle peut
exploiter la logique à multiple niveaux ainsi que les fonctions de résolution inhérentes à ces types. Cependant, il est pratique d’utiliser des types plus abstraits comme integer, character ou string,
mais il devient ensuite plus difficile, voire impossible, de retrouver ces signaux pour débogage dans les
produits de la synthèse ou de l’implémentation. Le concepteur doit donc choisir entre une représentation
plus abstraite qui facilite la description ou plus concrète pour gagner en visibilité dans le design.
Pour les constantes et les paramètres d’un module, on peut en général utiliser tous les types abstraits supportés par VHDL, comme par exemple real, integer, ou string.
4.5.4
Fils modélisés par les catégories signal et variable
En général, l’utilisation de la catégorie signal résulte en un fil concret dans un module. C’est moins
souvent le cas pour la catégorie variable, à cause du traitement différent de ces deux catégories.
L’Exemple 4-1 démontre ce principe. Trois assignations concurrentes sont effectuées aux signaux S1 et
S2 et au port F1 de l’entité. À l’intérieur d’un processus, trois assignations séquentielles sont effectuées à
la variable V puis sa valeur finale est assignée au port F2. Le comportement global du circuit est tel que
INF3500 : Conception et réalisation de systèmes numériques
54
v. 2.5, juillet 2013
Chapitre 4 : Flot de conception d’un circuit numérique
les ports de sortie F1 et F2 ont exactement la même valeur. La seule différence entre les deux approches
est que, dans le cas du processus, c’est le synthétiseur qui doit assigner des noms aux fils connectés à la
sortie des portes ET et OU du circuit. Lors de la simulation de celui-ci, il n’est pas possible d’observer ni
de forcer les valeurs sur ces fils.
library ieee;
use IEEE.STD_LOGIC_1164.ALL;
entity demoSignalVariable is
port (
A, B, C, D: in std_logic;
F1, F2 : out std_logic
);
end demoSignalVariable;
architecture demo of demoSignalVariable
is
signal S1, S2 : std_logic;
begin
S1 <= A and B;
S2 <= S1 or C;
F1 <= S2 nand D;
D
F1
C
B
A
S2
S1
D
F2
(V?)
C
process(A, B, C, D)
variable V : std_logic;
begin
V := A and B;
V := V or C;
V := V nand D;
F2 <= V;
end process;
B
A
V?
V?
end demo;
Exemple 4-1 – signaux et variables pour la modélisation
4.5.5
Boucles et conditions
À l’intérieur d’un processus, on peut utiliser des boucles et des conditions pour modéliser le comportement d’un circuit (voir la section 2.5.8). Les boucles et les conditions sont un outil puissant dans l’arsenal
du concepteur pour décrire un circuit complexe de façon concise et précise. Le but de cette section est de
décrire comment un outil de synthèse peut inférer des structures matérielles à partir de ces énoncés.
Les boucles sont implémentées en les déroulant, c'est-à-dire que les énoncés d’assignation qu’elles contiennent sont répliqués, un pour chaque itération de la boucle. Les paramètres d’exécution de la boucle
doivent prendre des valeurs statiques au moment de la synthèse. Les boucles sont une manière compacte
de représenter plusieurs énoncés reliés logiquement entre eux. La plupart des synthétiseurs supportent
aussi les clauses next (qui interrompt l’itération en cours de la boucle) et exit (qui termine la boucle).
Pour les circuits combinatoires, les conditions permettent d’effectuer un choix. Il y en a deux types : le if
et le case. L’énoncé case a l’avantage de représenter des choix qui sont mutuellement exclusifs et qui
ont la même préséance. Il correspond assez exactement à l’action d’un multiplexeur. L’énoncé if, quant
à lui, est plus général. Il peut comporter un ou plusieurs clauses elsif ainsi qu’une clause else. Il est
possible de l’utiliser pour donner préséance à certaines conditions par rapport à d’autres. Cela peut résulter en un circuit plus complexe que nécessaire, parce que le comportement décrit peut être plus restrictif
que ce que le concepteur a en tête.
INF3500 : Conception et réalisation de systèmes numériques
55
v. 2.5, juillet 2013
Chapitre 4 : Flot de conception d’un circuit numérique
4.5.6
Un mot sur l’inférence d’éléments à mémoire lors de la synthèse
Les outils de synthèse procèdent par analyse syntaxique du code et reconnaissent des structures spéciales
comme celles montrées dans les sections précédentes. Ils infèrent alors des composantes matérielles correspondantes. Il est important de vérifier la documentation d’un outil de synthèse pour savoir quelle structure de langage utiliser pour obtenir le type d’élément à mémoire désiré.
À l’intérieur d’un processus, un élément à mémoire est inféré en VHDL si un objet des catégories
signal ou variable se voit assigner une valeur dans un énoncé if-else, et que certains cas ne sont
pas couverts. Par exemple, dans l’Exemple 2-14, le cas G=’0’ n’est pas couvert. Les cas non couverts
impliquent que l’objet doit conserver sa valeur, et donc un loquet est inféré. Il est donc très important de
couvrir tous les cas possible avec une clause else quand on ne désire pas qu’un loquet soit inféré.
4.5.7
Distinctions entre la simulation et la synthèse
On remarque que la description du circuit en HDL peut être simulée et synthétisée. La simulation est
normalement faite en logiciel, alors que le but principal de la synthèse est d’obtenir un circuit matériel. La
simulation sert à vérifier la description du système en différents points du flot. Il peut arriver qu’une étape
du flot produise une description incorrecte, et la simulation permet de détecter cette erreur. Par exemple,
le processus de synthèse est très complexe, et peut inclure des suppositions qui ne sont pas évidentes lors
de la description du code original. Pour éviter ce genre de situation, les concepteurs d’outils de synthèse
publient des guides pour les concepteurs dans l’écriture de code HDL. Ces guides énumèrent des extraits
de code correspondant à des structures matérielles typiques. Il est donc utile pour le concepteur de bien
connaître son outil de synthèse pour s’assurer d’obtenir ce qu’il désire de cet outil.
4.6
Implémentation
Dans l’étape d’implémentation, on découpe la liste des interconnexions en composantes disponibles sur le
circuit intégré cible. L’implémentation comprend les étapes de placement et de routage. Le placement
consiste à disposer les composantes du circuit en rangées et en colonnes. Ce placement est souvent effectué de façon à respecter certaines contraintes de temps et/ou d’espace imposées par l’utilisateur. Le routage consiste à choisir les chemins suivis par les fils d’interconnexions entre les composantes du circuit.
Cette étape est soumise aussi à des contraintes, habituellement de temps. Les étapes de placement et routage sont répétées tant que les contraintes de temps et/ou d’espace ne sont pas satisfaites.
4.6.1
Association (Mapping)
Un synthétiseur produit en général une description du circuit en termes de composantes de base. Par
exemple, le synthétiseur XST de Xilinx génère une liste d’interconnexions de composantes tirées d’une
librairie générale applicable à tous les FPGAs de la compagnie et d’une librairie spécifique à la famille de
FPGA désignée par l’utilisateur. Les composantes de base incluent, entre autres :

des fonctions logiques comme ET, OU, OUX;

des multiplexeurs et décodeurs;

des additionneurs, soustracteurs, accumulateurs, multiplicateurs;

des bascules et loquets;

d’autres composantes comme des blocs de mémoire, des générateurs d’horloge et des tampons.
Le processus d’association (mapping) consiste à associer des composantes de base à des blocs ou des
groupes de blocs logiques du FPGA. Par exemple, un groupe de portes logiques peut être combiné en une
seule table de conversion d’un bloc logique. La Figure 4-3 illustre le processus d’association entre une
liste d’interconnexions et une table de conversion à trois entrées.
INF3500 : Conception et réalisation de systèmes numériques
56
v. 2.5, juillet 2013
Chapitre 4 : Flot de conception d’un circuit numérique
Portion of gate-level netlist
Contents of 3-input LUT
XOR
a
b
|
NOT
c
d
XNOR
|
y
e
a b c
y
0
0
0
0
1
1
1
1
0
1
1
0
1
0
0
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
Figure 4-3 – processus d’association
(source : fig. 8-8, Maxfield, © Mentor Graphics 2004)
Le processus d’association est rendu plus complexe par le fait que bien souvent une fonction logique a
plus d’entrées que les tables de conversion des blocs logiques. Il faut donc que l’outil d’association fasse
un partitionnement et une distribution de ces fonctions. Ce processus peut être très complexe parce qu’il
n’y a pas nécessairement qu’une seule solution. L’outil doit alors se baser sur des contraintes
d’optimisation imposées par l’utilisateur, comme une réduction de l’espace utilisé ou une réduction des
délais de propagation.
4.6.2
Placement et routage
Le processus de placement consiste à choisir un endroit spécifique sur le FPGA pour chacune des ressources nécessaires. Le processus de routage consiste à établir des connexions entre les ressources.
Le processus de placement est très complexe. En pratique, on voudrait que des blocs qui communiquent
entre eux soient disposés près les uns des autres. De cette façon, on simplifierait la tâche du routeur et on
diminuerait les délais dus aux interconnexions. Cependant, dans le cas d’une composante avec des liens
vers beaucoup d’autres, ce n’est pas possible. De plus, si on utilise une grande proportion des ressources
du FPGA (> 80%), le placeur n’a pas beaucoup de marge de manœuvre. Les algorithmes de placement
utilisent souvent des méthodes heuristiques comme le recuit simulé.
Le processus de routage est aussi très complexe, et est souvent basé lui aussi sur des méthodes heuristiques. Le problème vient du fait qu’il existe un nombre limité de ressources d’interconnexions entre les
blocs logiques d’un FPGA. Il peut donc être impossible de router un circuit étant donné un placement.
Dans un tel cas, le placeur doit effectuer un nouveau placement pour donner plus de flexibilité au routeur.
4.7
Extraction de métriques et annotation des délais
Une fois l’implémentation terminée, on obtient un fichier qui décrit toutes les interconnexions et la configuration des blocs logiques du FPGA.
On obtient aussi une liste des interconnexions dans laquelle sont annotés les délais de chaque composante
ainsi que les délais de routage. Comme les FPGAs ont une structure très régulière, la précision de ces
délais est conforme aux spécifications du manufacturier et est excellente par rapport à une puce donnée.
INF3500 : Conception et réalisation de systèmes numériques
57
v. 2.5, juillet 2013
Chapitre 4 : Flot de conception d’un circuit numérique
On peut donc simuler cette liste des interconnexions avec le même banc d’essai initial, ou même un plus
sophistiqué qui tient en compte les délais attendus du système. Cette simulation prend en général un ordre
de grandeur supplémentaire en temps à faire que la simulation de la description initiale du circuit à cause
du très grand nombre de composantes et de fils dont le simulateur doit tenir compte.
On obtient aussi un rapport détaillé sur les ressources utilisées sur le FPGA, ainsi qu’une description du
chemin critique avec le délai sur celui-ci.
Si les spécifications ne sont pas rencontrées, on peut alors retourner à l’une des étapes du flot de conception pour corriger les problèmes.
4.8
Génération du fichier de configuration et programmation
La dernière étape consiste en général à programmer le dispositif devant supporter le circuit ou à faire
dessiner les masques qui permettront de construire des transistors à partir de semi-conducteurs dopés et
d’isolants ainsi que les connexions métalliques qui les relieront.
L’action de programmer un FPGA consiste à configurer tous ses blocs logiques, ses blocs d’entrées et
sorties et ses interconnexions. Par exemple, pour le bloc logique simplifié de la Figure 3-13, il faut programmer les deux tables de conversion de 16 bits chacune et les quatre multiplexeurs de contrôle, pour un
total de 38 cellules de programmation ou environ 5 octets. Le fichier de configuration contient typiquement quelques mégaoctets de données de programmation.
Afin de programmer efficacement un FPGA, on peut imaginer que toutes les cellules de programmation
sont placées en série. Un signal spécial permet de les placer en mode de programmation, où chaque cellule passe son contenu à la prochaine cellule à chaque coup d’horloge. Ce système permet d’effectuer la
programmation du dispositif avec très peu de pattes : une pour le signal de programmation, une pour placer les cellules en mode de programmation, une pour lire le flux de bits de programmation pour fins de
vérification, et une horloge de programmation.
Le processus est montré conceptuellement à la Figure 4-4. En pratique, la programmation s’effectue par
groupes de cellules dans un processus série-parallèle.
Configuration data in
Configuration data out
= I/O pin/pad
= SRAM cell
Figure 4-4 – programmer un FPGA
(source : fig. 5-3, Maxfield, © Mentor Graphics 2004)
INF3500 : Conception et réalisation de systèmes numériques
58
v. 2.5, juillet 2013
Chapitre 4 : Flot de conception d’un circuit numérique
4.9
Exercices
1. Considérez le problème de conception d’un téléviseur à haute définition. Proposez une décomposition
de ce système en modules et faites un partitionnement initial logiciel-matériel.
2. Donnez les avantages et les inconvénients de la description d’un circuit numérique avec un schéma de
composantes, du code VHDL ou un diagramme d’états.
3. Discutez de l’affirmation suivante : « Avec la venue des HDL, la conception de systèmes numériques
s’apparente plus à du génie logiciel que de systèmes matériels ». Êtes-vous d’accord? Pourquoi?
4. Expliquer la différence entre les étapes de synthèse et d’implémentation.
5. Expliquez pourquoi tout l’ensemble du langage VHDL n’est pas synthétisable.
6. Expliquez les défis de synthétiser du code écrit en C par rapport à du code VHDL.
7. Dans quelles conditions l’utilisation d’une boucle est-elle synthétisable? Donnez un exemple et un
contre-exemple.
8. Consultez les rapports des outils de synthèse et d’implémentation de l’un de vos laboratoires. Comparez les métriques de coût et de performance déterminés aux différentes étapes du processus. L’estimé
initial du synthétiseur était-il bon?
9. Proposez une cellule de programmation pour un FPGA, composée d’une bascule et de quelques
portes logiques. La cellule doit avoir un signal de contrôle pour la placer en mode de programmation.
Dans ce mode, elle utilise une entrée et une sortie spéciales qui la placent dans une chaîne de bascules, comme montré à la Figure 4-4. Montrez trois bascules ainsi reliées.
INF3500 : Conception et réalisation de systèmes numériques
59
v. 2.5, juillet 2013
Chapitre 4 : Flot de conception d’un circuit numérique
INF3500 : Conception et réalisation de systèmes numériques
60
v. 2.5, juillet 2013
Chapitre 5
Conception de chemins des données
Ce chapitre débute par une description du concept de processeur. Ensuite, il considère le problème de la
conception du chemin des données d’un processeur, c'est-à-dire la partie qui effectue le traitement de
l’information. La conception de l’unité de contrôle du processeur est considérée au Chapitre 6.
5.1
Les processeurs
5.1.1
Types de processeurs
Un processeur est un type spécial de système numérique dont le but est de traiter des données par une
succession d’étapes simples. Le traitement global effectué peut être relativement complexe. Deux
exemples de processeurs sont une machine distributrice et un appareil d’imagerie médicale par ultrasons.
Dans ces deux cas, le système doit acquérir des données, les traiter et produire un résultat sous forme
numérique ou vidéo. Le traitement des données doit être fait dans un ordre précis selon des signaux de
contrôle.
On distingue deux types principaux de processeurs :

Les processeurs à usage général peuvent être programmés et sont donc très polyvalents. Le programme exécuté par un processeur est gardé en mémoire sous la forme d’une liste d’instructions. On
réfère souvent à ce type de processeur par le nom de « microprocesseur » ou « unité centrale de traitement » (Central Processing Unit – CPU). Les processeurs spécialisés sont des processeurs à usage
général auxquels on a ajouté des composantes supplémentaires pour pouvoir exécuter des instructions
spéciales nécessaires dans certaines classes d’applications comme le traitement du signal ou des
images. Les microcontrôleurs sont des processeurs spécialisés qui peuvent inclure de la mémoire, des
unités d’entrée-sortie élaborées et d’autres périphériques.

Les processeurs à usage spécifique sont des processeurs non programmables qui sont conçus dans le
but de répondre à un besoin unique. Ils sont plus simples et plus efficaces que les processeurs à usage
général, mais ils ne peuvent pas en général être facilement reprogrammés. La plupart des périphériques d’un ordinateur contiennent au moins un processeur à usage spécifique, comme par exemple un
coprocesseur mathématique, un gestionnaire de bus ou un module d’interface réseau.
5.1.2
Parties d’un processeur
Un processeur peut être décomposé en deux parties principales, montrées à la Figure 5-1.
Sortie des données
Entrée des données
Chemin des données
État
Contrôle
Entrées de contrôle
Sorties de contrôle
Unité de contrôle
Figure 5-1 – architecture générale d’un processeur
INF3500 : Conception et réalisation de systèmes numériques
61
v. 2.42, décembre 2009
Chapitre 5 : Conception de chemins des données

Le chemin des données (datapath) inclut des registres et des unités fonctionnelles, comme une unité
arithmétique et logique, ainsi qu’un mécanisme de commutation pour transférer et manipuler les données. Le chemin des données reçoit des données du monde extérieur, effectue des calculs et produits
des résultats. Il reçoit aussi des signaux de l’unité de contrôle indiquant les opérations à effectuer. Il
transmet à l’unité de contrôle des signaux indiquant l’état des opérations effectuées.

L’unité de contrôle, ou unité de commande (control unit) est responsable du séquençage des opérations à exécuter par le chemin de données selon des entrées externes et le résultat des opérations. Elle
peut recevoir des signaux de contrôle en entrée et en produire pour d’autres unités. Elle reçoit des indicateurs d’état du chemin des données et lui transmet des commandes.
5.2
Approche RTL : principes et notation
5.2.1
Architecture générale d’un chemin de données
Un chemin des données est composé de deux parties principales montrées à la Figure 5-2.
Entrées
Unités fonctionnelles et
modules combinatoires
Registres
Horloge
charger
registres à
charger
registres à
lire
opération
Sorties
état
Figure 5-2 – architecture générale du chemin des données
La première partie renferme des éléments à mémoire, habituellement sous la forme d’un bloc de registres.
Ces registres conservent les données à traiter et des résultats qui peuvent avoir été calculés plus tôt, de
façon à pouvoir combiner toutes ces valeurs dans de nouveaux calculs. Les éléments à mémoire sont décrits en détail à la section 5.4.
Les unités fonctionnelles effectuent des opérations sur les données conservées dans les registres. Elles
reçoivent un signal de contrôle indiquant l’opération à effectuer. Elles peuvent émettre un signal d’état
donnant de l’information sur le résultat de l’opération, comme par exemple que le résultat est nul ou négatif. La sortie de l’unité fonctionnelle est reliée à l’entrée du bloc des registres afin de sauvegarder le résultat de l’opération. Les unités fonctionnelles sont décrites à la section 5.5.
Des modules combinatoires permettent de choisir, router et contrôler le flot d’information entre les registres et les unités fonctionnelles. Les modules combinatoires sont décrits à la section 5.3.
5.2.2
Conception de chemins des données : approche RTL
L’approche RTL (Register Transfer Level) est la plus populaire pour la conception de chemins des données. Elle est basée sur l’architecture suggérée à la Figure 5-1, et a l’avantage de correspondre grosso
modo aux langages de description matérielle comme VHDL et Verilog.
Dans l’approche RTL, le concepteur spécifie les registres du processeur, les transferts de données entre
ces registres, les opérations à effectuer et les signaux de contrôle pour gérer ces activités.
L’approche RTL peut être décomposée en quatre étapes :
1. Analyse détaillée du problème afin de bien comprendre le flot des données à travers le processeur.
2. Conception du chemin des données et identification des signaux de contrôle et d’état.
INF3500 : Conception et réalisation de systèmes numériques
62
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
3. Conception de l’unité de contrôle du processeur à l’aide d’une machine à états générant des signaux
de contrôle (vue au Chapitre 6).
4. Vérification que le processeur résultant rencontre les spécifications.
5.2.3
Micro-opérations
Une micro-opération est une opération élémentaire effectuée sur les données gardées en mémoire ou des
données externes. La spécification d’une micro-opération inclut :

les opérandes (registres ou données externes);

la nature de la micro-opération à effectuer;

l’endroit où le résultat de la micro-opération doit être sauvegardé; et,

une condition à remplir pour que la micro-opération soit effectuée.
On distingue quatre types principaux de micro-opérations :

les transferts entre registres;

les micro-opérations arithmétiques (addition, soustraction, multiplication, division, reste)

les micro-opérations logiques (NON, ET, OU, OUX, etc.); et,

le décalage.
Le Tableau 5-1 contient quelques exemples de micro-opérations. Les identificateurs R0, R1, etc. réfèrent
à des registres en particulier. Le symbole ← indique une assignation de valeur. Les opérateurs sont définis
dans le tableau.
Micro-opération
Signification
R0 ← R1
Copier le contenu de R1 dans R0.
R2 ← R1 + R3
Placer la somme de R1 et de R3 dans R2.
R2 ← R2 ET R3
Placer le résultat de l’opération ET logique entre R2 et R3 dans R2.
K1 : R2 ← sll R1, 3
Si le signal de contrôle K1 est actif, placer dans R2 le résultat du décalage logique vers la gauche de 3 positions du registre R1; sinon, ne
rien faire.
R2 ← R1 − R3; R4 ← R0
Simultanément, placer la différence entre R1 et R3 dans R2 et copier
le contenu de R0 dans R4.
Tableau 5-1 - exemples de micro-opérations
5.2.4
Synchronisation
Dans la Figure 5-2, le bloc des registres est contrôlé par un signal d’horloge. À chaque coup d’horloge, le
bloc des registres peut emmagasiner une nouvelle donnée provenant du port des entrées, un résultat qui
vient d’être calculé par l’unité fonctionnelle, ou bien effectuer un transfert entre deux registres, comme
indiqué dans le Tableau 5-1. Plusieurs micro-opérations peuvent être effectuées simultanément.
Une fois le coup d’horloge passé, l’unité fonctionnelle effectue les calculs spécifiés par le code
d’opération qui lui est appliqué, et tout résultat et état du résultat sont appliqués à ses ports de sortie. Le
bloc des registres ne saisit quand à lui ce nouveau résultat que lors de la prochaine transition d’horloge.
Les micro-opérations ne prennent effet que lors d’une transition active du signal d’horloge du chemin des
données.
INF3500 : Conception et réalisation de systèmes numériques
63
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
5.3
Modules combinatoires utilisés dans les chemins des données
5.3.1
Multiplexeurs
Un multiplexeur permet de choisir un seul signal à partir d’un ensemble de signaux, selon la valeur d’un
signal de contrôle.
Un multiplexeur a :

un groupe de signaux d’entrée D;

un groupe de signaux de contrôle S (pour sélection); et,

un signal de sortie F.
Le signal de sortie est égal au signal d’entrée choisi par les signaux de contrôle. En général, un multiplexeur a exactement n signaux de contrôle et 2n signaux d’entrées. Chacun des signaux d’entrée peut être
un fil unique ou un bus de plusieurs fils. Un multiplexeur peut être vu comme un commutateur à plusieurs
positions. L’équation booléenne de sortie d’un multiplexeur avec n signaux de contrôle et 2n signaux
d’entrées est donnée par:
2n 1
F   mk Dk
k 0
où mk est un minterme formé par la kième combinaison de signaux de contrôle S. Par exemple,
l’équation booléenne d’un multiplexeur 2:1 est :
F  S ' D0  SD1
c’est à dire que si le signal de contrôle S vaut ‘1’, alors la sortie F est égale à l’entrée D1. Sinon, la sortie
F est égale à l’entrée D0.
Pour un multiplexeur 4:1, il y a deux signaux de contrôle S1 et S0, quatre signaux d’entrée D3, D2, D1, D0,
et un signal de sortie F. Les deux bits S1 et S0 prennent l’une de 4 combinaisons 00, 01, 10, ou 11, indiquant laquelle des entrées Di est connectée à la sortie F.
La Figure 5-3 montre les symboles et les schémas d’un multiplexeur 2:1 et d’un multiplexeur 4:1.
D0
D0
0
S
F
D1
F
1
D1
S
S1
S0
D0
D0
0
D1
D2
1
D3
3
2
F
D1
F
D2
S1
D3
S0
Figure 5-3 - multiplexeurs 2:1 et 4:1
INF3500 : Conception et réalisation de systèmes numériques
64
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
La description d’un multiplexeur en VHDL peut être faite de plusieurs façons. L’Exemple 5-1 est un flot
de données simple pour un multiplexeur 2:1. On remarque qu’il n’est pas nécessaire d’énoncer les équations booléennes du circuit. Une assignation choisie couvrant tous les cas possibles de façon exclusive est
suffisante pour modéliser adéquatement un multiplexeur.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity mux21 is
port(D0, D1, S : in STD_LOGIC; F : out STD_LOGIC);
end mux21;
architecture flotDeDonnees of mux21 is
begin
with S select
F <= D0 when '0', D1 when others;
end flotDeDonnees;
Exemple 5-1 – multiplexeur 2:1
Une description comportementale décrit efficacement un multiplexeur dont le nombre de signaux d’entrée
est déterminé uniquement au moment de l’instanciation du module. Ceci est démontré dans l’Exemple
5-2. Comme dans l’Exemple 2-11, on paramètre le nombre d’entrées du multiplexeur à l’aide de l’énoncé
generic. On spécifie ici le nombre de signaux de contrôle, qui est relié au nombre d’entrées du multiplexeur par une puissance de deux. La fonction to_integer du package numeric_std permet
d’exprimer toutes les valeurs possibles du signal de sélection.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mux is
generic (
n : positive := 3 -- nombre de signaux de contrôle
);
port (
D : in std_logic_vector(2 ** n - 1 downto 0);
S: in unsigned(n - 1 downto 0);
F : out std_logic
);
end mux;
architecture comportementale of mux is
begin
process (D, S)
begin
F <= D(to_integer(S));
end process;
end comportementale;
Exemple 5-2 – description comportementale d’un multiplexeur général
5.3.2
Décodeurs
Un décodeur active un signal spécifique correspondant à un code numérique en particulier.
Un décodeur a n signaux d’entrée et 2n signaux de sortie. Chacun des signaux de sortie correspond à un
des mintermes et maxtermes composés des signaux d’entrée. Exactement une ligne de sortie est active à
un moment donné. Le numéro de cette ligne correspond à la valeur binaire appliquée aux lignes d’entrée.
Selon les décodeurs, la ligne active pourra être à une valeur 0 ou une valeur 1, et toutes les autres lignes
INF3500 : Conception et réalisation de systèmes numériques
65
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
seront à l’autre valeur. Le Tableau 5-2 donne la table de vérité d’un décodeur 3:8 pour lequel les entrées
sont A(2:0), les sorties sont F(7:0), et la valeur ‘1’ est considérée comme active.
#
A2
A1
A0
F7
F6
F5
F4
F3
F2
F1
F0
0
1
2
3
4
5
6
7
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
0
Tableau 5-2 – table de vérité d’un décodeur 3:8
Le modèle en VHDL pour ce décodeur est donné à l’Exemple 5-3. Une assignation choisie permet de
spécifier les huit cas possibles du signal d’entrée F. Dans le modèle, l’utilisation de la clause others
permet de rendre le modèle plus robuste à la simulation. En effet, le type std_logic peut prendre des
valeurs autres que ‘0’ et ‘1’ – voir la section 2.5.4. Lors de la simulation, si le signal F prend une valeur
comme « X1W », la sortie du décodeur sera un vecteur de ‘X’. L’expression (others => ‘X’) permet d’assigner la valeur ‘X’ à chacun des éléments du vecteur F.
library ieee;
use ieee.std_logic_1164.all;
entity decodeur38 is
port(
A : in std_logic_vector(2 downto 0);
F: out std_logic_vector(7 downto 0)
);
end decodeur38;
architecture flotDeDonnees of decodeur38 is
begin
with A select F <=
"00000001" when "000",
"00000010" when "001",
"00000100" when "010",
"00001000" when "011",
"00010000" when "100",
"00100000" when "101",
"01000000" when "110",
"10000000" when "111",
(others => 'X') when others;
end flotDeDonnees;
Exemple 5-3 – décodeur 3:8
Une version générale du décodeur est donnée dans l’Exemple 5-4 sous la forme d’une description comportementale concise. Deux paramètres sont utilisés. Le premier spécifie le nombre de signaux d’entrée et
le deuxième spécifie la valeur à utiliser pour la sortie active.
INF3500 : Conception et réalisation de systèmes numériques
66
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity decodeur is
generic (
n : positive := 3; -- nombre de signaux d'entrée
valeurActive : std_logic := '1'
);
port(
A : in std_logic_vector(n - 1 downto 0);
F: out std_logic_vector(2 ** n - 1 downto 0)
);
end decodeur;
architecture comportementale of decodeur is
begin
process(A)
begin
F <= (others => not(valeurActive));
F(to_integer(unsigned(A))) <= valeurActive;
end process;
end comportementale;
Exemple 5-4 – décodeur général
On exploite le fait que les énoncés sont exécutés de façon séquentielle à l’intérieur d’un processus. Toutes
les sorties sont désactivées. Ensuite, seule celle dont le numéro correspond au signal d’entrée est activée.
Contrairement à l’Exemple 5-3, il n’est pas possible d’assigner une valeur inconnue aux signaux de sortie.
5.3.3
Encodeurs à priorité
Un encodeur identifie un signal actif parmi un ensemble de signaux, et produit un code qui correspond à
ce signal actif.
Un encodeur fonctionne de façon contraire à un décodeur. Il a n lignes de sortie et 2n lignes d’entrée. Le
code à la sortie représente le numéro de la ligne qui est active. Un encodeur à priorité permet d’avoir plus
d’une ligne d’entrée active à la fois. La priorité peut être accordée à la ligne ayant le plus grand ou le plus
petit numéro. Un signal spécial est requis pour indiquer qu’au moins une des lignes en entrée est active.
Le Tableau 5-3 contient une table de vérité correspondant à un encodeur à priorité à 8 lignes d’entrée,
avec priorité aux lignes d’entrée à numéro élevé.
D7
D6
D5
D4
D3
D2
D1
D0
A2
A1
A0
V
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
1
-
0
0
0
0
0
0
1
-
0
0
0
0
0
1
-
0
0
0
0
1
-
0
0
0
1
-
0
0
1
-
0
1
-
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
1
1
1
1
1
1
1
1
Tableau 5-3 – table de vérité d’un encodeur à priorité 8:3
INF3500 : Conception et réalisation de systèmes numériques
67
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
L’Exemple 5-5 démontre un modèle VHDL synthétisable pour un encodeur à priorité général. Le nombre
de bits nécessaires pour encoder le numéro de la ligne d’entrée active ainsi que la valeur du signal actif
sont paramétrés. La priorité est donnée aux lignes avec un numéro élevé, comme dans le Tableau 5-3. Au
début du processus, on donne une valeur par défaut aux signaux de sortie V et A, au cas où aucune des
entrées n’est active. La valeur par défaut donnée au signal A est un « peu-importe » (don’t-care), représenté pour le type std_logic par un tiret ‘-‘. Ensuite, une boucle permet d’inspecter chaque bit du signal d’entrée pour déterminer si sa valeur correspond à la valeur active.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity encodeurP is
generic (
n : positive := 3; -- largeur du code de sortie
valeurActive : std_logic := '1' -- valeur de signal d'entrée actif
);
port(
D : in std_logic_vector(2 ** n - 1 downto 0); -- le bus d'entrée
A : out std_logic_vector(n - 1 downto 0); -- le code de sortie
V : out std_logic -- '1' si au moins un signal d'entrée est actif
);
end encodeurP;
architecture comportementale of encodeurP is
begin
process(D)
begin
-- des valeurs par défaut sont essentielles
-- au cas où aucun signal d'entrée n'est actif
V <= '0';
A <= (others => '-');
for k in 2 ** n - 1 downto 0 loop -- priorité aux valeurs élevées
if D(k) = valeurActive then
A <= std_logic_vector(to_unsigned(k, n));
V <= '1';
exit; -- termine la boucle
end if;
end loop;
end process;
end comportementale;
Exemple 5-5 – encodeur à priorité
5.3.4
Tampons à trois états
Il est parfois nécessaire de relier la sortie de plusieurs circuits entre eux, par exemple pour partager un bus
de communications. Le problème, c’est qu’un seul circuit devrait contrôler le bus à la fois, sinon on risque
d’avoir un circuit qui mène un ‘0’ alors qu’un autre circuit mène un ‘1’, ce qui créerait un court-circuit et
détruirait la composante. Une solution consiste à utiliser des multiplexeurs avec un signal pour choisir
quel circuit est actif à un moment donné. Cette solution est coûteuse parce que les multiplexeurs larges
nécessitent beaucoup de portes logiques.
Une solution plus économique consiste à utiliser des tampons à trois états : ‘1’, ‘0’ et ‘haute impédance’.
Dans l’état de haute impédance, la sortie du circuit est flottante. Elle est effectivement déconnectée électriquement du système.
INF3500 : Conception et réalisation de systèmes numériques
68
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
En VHDL, on peut modéliser un tampon à trois états assez simplement, tel que montré dans l’Exemple
5-6. On utilise la valeur ‘Z’ du type std_logic qui correspond à un état de haute impédance.
library ieee;
use ieee.std_logic_1164.all;
entity tampon3etats is
port(
I : in std_logic; -- signal d'entrée
S : in std_logic; -- signal de contrôle
O : out std_logic -- signal de sortie
);
end tampon3etats;
architecture flotdonnees of tampon3etats is
begin
O <= I when (S = '1') else 'Z';
end flotdonnees;
Exemple 5-6 – tampon à trois états
5.4
Éléments à mémoire pour chemins des données
5.4.1
Registres à chargement parallèle
Un registre est l’élément à mémoire de base pour des données. Un registre est utilisé pour entreposer une
information, encodée sur un groupe de bits, comme par exemple un octet de mémoire dans un ordinateur
ou le contenu de l’accumulateur d’une calculatrice.
Un registre est composé d’un groupe de bascules contrôlées par une horloge commune et dont les entrées
et sorties partagent un identificateur commun. Chaque bascule du registre est différenciée des autres par
un indice unique.
Un registre à chargement parallèle comporte un signal de chargement qui permet de moduler le signal
d’horloge. Quand ce signal est actif, le contenu du registre est modifié sur une transition de l’horloge.
Dans le cas contraire, le contenu du registre reste inchangé.
Un registre à chargement parallèle à 4 bits est montré à la Figure 5-4. Dans la figure, une seule bascule est
montrée mais il y en a en fait quatre empilées. Le modèle VHDL d’un registre à chargement parallèle est
montré à l’Exemple 5-7. Un énoncé generic permet de varier la largeur du registre lors de son instanciation.
0
D3:D0
charge
/
4
1
D
Q
CLK
Q'
clk
/
4
Q3:Q0
Figure 5-4 – registre à 4 bits à chargement parallèle
INF3500 : Conception et réalisation de systèmes numériques
69
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity registre is
generic (
W : integer := 8
);
port(
reset : in STD_LOGIC;
CLK : in STD_LOGIC;
charge : in STD_LOGIC;
D : in STD_LOGIC_VECTOR(W - 1 downto 0);
Q : out STD_LOGIC_VECTOR(W - 1 downto 0)
);
end registre;
architecture arch of registre is
begin
process (CLK, reset)
begin
if reset='0' then
Q <= (others => '0');
elsif CLK='1' and CLK'event then
if charge='1' then
Q <= D;
end if;
end if;
end process;
end arch;
Exemple 5-7 – registre à chargement parallèle
5.4.2
Registres à décalage
Un registre à décalage peut, comme son nom l’indique, décaler ses bits vers la gauche ou la droite, en
général d’une seule position à la fois. Il a une entrée supplémentaire par direction de décalage possible,
permettant de faire charger son contenu de façon sérielle un bit à la fois. Un registre à décalage peut être
construit par une cascade de bascules D dont la sortie est reliée à l’entrée de la bascule suivante.
Un registre à décalage peut être utilisé pour faire une conversion entre les formats série et parallèle et est
donc une composante fondamentale de plusieurs circuits de communication.
Un registre à décalage permet aussi d’effectuer la multiplication par deux, qui correspond à un décalage
de bits vers la gauche, et la division par deux, qui correspond à un décalage vers la droite. Dans le cas de
la multiplication, l’entrée série doit être ‘0’. Dans le cas de la division, pour des nombres non signés
l’entrée série doit être un ‘0’. Pour les nombres signés, cependant, l’entrée série doit être identique au bit
le plus significatif pour conserver le signe du nombre et obtenir un résultat correct.
Un registre à décalage de 4 bits est montré à la Figure 5-5. Le modèle VHDL d’un registre à décalage de
largeur arbitraire est donné à l’Exemple 5-8. Le registre a une entrée de deux bits, mode, qui détermine
son comportement. Les modes « 00 » et « 01 » correspondent au comportement d’un registre à chargement parallèle de base. Les modes « 10 » et « 11 » permettent de décaler le contenu du registre vers la
gauche ou la droite, dans chaque cas en introduisant un nouveau bit de l’entrée spéciale entreeSerie.
5.4.3
Conception d’un bloc de registres
Un bloc de registres (register file) regroupe plusieurs registres d’un chemin des données. C’est effectivement une petite mémoire qui rassemble plusieurs des données du circuit. Il est composé de plusieurs re-
INF3500 : Conception et réalisation de systèmes numériques
70
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
gistres de largeurs identiques qui partagent des ports d’entrée et de sortie. Le nombre de registres peut
varier de 1 seul à 1024, et leur largeur peut varier de 4 à 128 bits. Par exemple, pour un microprocesseur
de 32 ou 64 bits, le nombre réfère à la largeur des registres du bloc des registres.
Q0
D0
entreeSerie
Q1
0
1
Q
CLK
Q'
D
Q
CLK
Q'
D
Q
CLK
Q'
D
Q
CLK
Q'
Q0
3
Q1
D1
Q0
Q2
0
1
2
Q1
3
Q2
D2
Q1
Q3
0
1
Q2
2
3
Q3
D3
Q2
entreeSerie
mode
D
2
0
1
2
Q3
3
/
2
Figure 5-5 – registre à 4 bits à décalage et à chargement parallèle
Le bloc des registres a en général plusieurs ports d’entrée et de sortie indépendants. Des signaux de contrôle permettent de choisir quel registre est dirigé à chacune des sorties, et quels registres doivent être
chargés. Le modèle de bloc de registres décrit ici a un port d’entrée et deux ports de sortie. Il est possible
d’augmenter le nombre de ces ports selon les besoins.
La Figure 5-6 illustre un bloc de quatre registres dont les sorties sont contrôlées par multiplexeurs. Deux
multiplexeurs reçoivent en entrée la sortie de chacun des registres, et les signaux de contrôle choixA et
choixB permettent de choisir quel registre est dirigé à chacune des sorties.
Pour charger les registres, un décodeur reçoit un signal de deux bits, choixCharge, et active l’une de
quatre sorties. Chacun de ces signaux est combiné avec le signal charge dans une porte ET avant d’être
connecté au port de chargement de chacun des registres. Les entrées des registres sont toutes reliées au
signal d’entrée donnée.
La Figure 5-6 n’inclut ni les signaux d’horloge ni les signaux de réinitialisation des registres.
Le désavantage de cet arrangement est le grand nombre de connexions requises aux multiplexeurs de
sortie. Dans la Figure 5-6, on a fait abstraction de la largeur des registres. Pour un bloc avec des registres
de 64 bits, il faut alors avoir 128 multiplexeurs pour contrôler chacun des bus de sortie A et B. Plus que
les multiplexeurs, c’est le routage des fils à la sortie des registres qui est problématique et qui risque de
ralentir le circuit.
INF3500 : Conception et réalisation de systèmes numériques
71
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity registreadecallage is
generic (
W : integer := 8 -- nombre de bits du registre
);
port(
reset : in STD_LOGIC;
CLK : in STD_LOGIC;
mode : in STD_LOGIC_VECTOR(1 downto 0); -- mode
entreeSerie : in STD_LOGIC; -- entree serielle
D : in STD_LOGIC_VECTOR(W - 1 downto 0);
Q : out STD_LOGIC_VECTOR(W - 1 downto 0)
);
end registreadecallage;
architecture arch of registreadecallage is
begin
process (CLK, reset)
variable Qinterne : STD_LOGIC_VECTOR(W - 1 downto 0);
begin
if reset='0' then
Qinterne := (others => '0');
Q <= (others => '0');
elsif CLK='1' and CLK'event then
case mode is
when "00" => -- garde
Qinterne := Qinterne;
when "01" => -- charge
Qinterne := D;
when "10" => -- decale gauche
Qinterne := Qinterne(W - 2 downto 0) & entreeSerie;
when "11" => -- decale droite
Qinterne := entreeSerie & Qinterne(W - 1 downto 1);
when others =>
Qinterne := Qinterne;
end case;
Q <= Qinterne;
end if;
end process;
end arch;
Exemple 5-8 – registre à décalage
Une organisation plus efficace du point de vue du routage des signaux de sortie est montrée à la Figure
5-7. Ici, on utilise des bus avec des tampons à trois états. Les tampons à trois états sont décrits à la section
5.3.4. À chaque registre est associé un tampon qui mène un bus. Un signal de contrôle permet de connecter ou non la sortie du tampon au bus. Les signaux de contrôle (R0A, R1A, etc.) sont générés à l’aide de
deux décodeurs 2:4 menés par les signaux choixA et choixB.
Le mécanisme de chargement est identique à celui de la Figure 5-6.
INF3500 : Conception et réalisation de systèmes numériques
72
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
D
donnée
Q
R0
charge
charge
choixA
D
Q
A
2:4
choixCharge
R1
charge
0
1
2
3
D
Q
R2
charge
choixB
B
D
Q
R3
charge
Figure 5-6 – bloc des registres avec multiplexeurs
R0A
D
donnée
Q
R0B
R0
charge
charge
A
B
R1A
D
Q
R1B
2:4
2:4
choixCharge
R1
charge
0
1
2
3
choixA
0
1
2
3
R0A
R1A
R2A
R3A
R2A
D
Q
R2B
2:4
R2
charge
choixB
R3A
D
Q
0
1
2
3
R0B
R1B
R2B
R3B
R3B
R3
charge
Figure 5-7 – bloc des registres avec bus et tampons à trois états
INF3500 : Conception et réalisation de systèmes numériques
73
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
L’Exemple 5-9 illustre la description du bloc des registres en VHDL. Les registres sont représentés à
l’aide d’un tableau d’objets de type signed. Un processus définit le comportement du bloc des registres
comme des bascules activées sur une transition positive du signal d’horloge. Les deux bus de sortie du
bloc des registres sont décrits par des énoncés concurrents à l’extérieur du processus.
-- dans la partie déclarative de l’architecture
type lesRegistres_type is array(0 to Nreg - 1) of signed(Wd - 1 downto 0);
signal lesRegistres : lesRegistres_type;
signal A : signed(Wd - 1 downto 0);
signal choixA : integer range 0 to Nreg - 1;
signal B : signed(Wd - 1 downto 0);
signal choixB : integer range 0 to Nreg - 1;
signal donnee : signed(Wd - 1 downto 0);
signal choixCharge : integer range 0 to Nreg - 1;
signal charge : std_logic;
-- dans le corps de l’architecture
process (CLK, reset)
begin
if rising_edge(CLK) then
if reset = '1' then
lesRegistres <= (others => (others => '0'));
else
if charge = '1' then
lesRegistres(choixCharge) <= donnee;
end if;
end if;
end if;
end process;
-- signaux de sortie du bloc des registres
A <= lesRegistres(choixA);
B <= lesRegistres(choixB);
Exemple 5-9 – bloc des registres
On note que rien dans le code VHDL ne spécifie si des multiplexeurs ou des tampons à trois états sont
utilisés. Pour spécifier ce comportement dans le code, il faudrait utiliser une description structurale (voir
la section 2.3.2). Certains synthétiseurs permettent aussi de forcer le style d’implémentation des multiplexeurs. D’autres sont suffisamment sophistiqués pour choisir le style le plus efficace selon la technologie ciblée.
La réinitialisation du bloc des registres est décrite avec l’expression (others=>(others=>'0'))
qui imbrique deux clauses others. Cela est nécessaire parce que le bloc des registres est une structure
de données à deux dimensions.
Le code de l’Exemple 5-9 exploite le type integer pour spécifier les registres à charger et de sortie.
Cela clarifie grandement le code. Il est important cependant de spécifier les gammes de valeurs attendues,
sinon le synthétiseur produira un circuit beaucoup plus complexe que nécessaire afin de pouvoir accommoder toutes les valeurs possibles correspondant à ce type.
Le code de l’Exemple 5-9 exploite aussi l’utilisation de paramètres pouvant être déclarés avec des énoncés generic. Ces paramètres sont Nreg pour le nombre de registres et Wd pour la largeur du chemin
des données en bits.
INF3500 : Conception et réalisation de systèmes numériques
74
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
5.4.4
Mémoires vives (RAM)
Une mémoire vive peut être vue comme un bloc de registres de très grande taille. Elle a en général un port
de sortie, un port d’entrée, un port d’adresse et un port de contrôle de l’opération. À l’image du bloc des
registres, la mémoire peut avoir plusieurs ports d’entrée et de sortie. En général, il est utile que les cellules de la mémoire aient est la même taille que celles du bloc des registres, mais ce n’est pas strictement
nécessaire.
La description d’une mémoire des données en VHDL peut prendre plusieurs formes, selon une multitude
de paramètres. Ceux-ci incluent, entre autres :

le nombre de ports d’entrée et de sortie;

le fait que les sorties soient synchrones ou asynchrones;

le nombre de cycles nécessaires à la mémoire pour déplacer des données;

la présence de signaux d’activation; et,

la spécification de valeurs initiales.
Du code VHDL pour une mémoire des données est montré à l’Exemple 5-10. Pour simplifier les choses,
la description est virtuellement identique à celle du bloc des registres de l’Exemple 5-9. En pratique, la
lecture d’une donnée en mémoire nécessite un cycle d’horloge pour charger l’adresse à lire. Le contenu
de la cellule de mémoire correspondante n’est disponible qu’au cycle suivant, ou, dans le cas de certaines
mémoires, plusieurs cycles plus tard.
-- dans la partie déclarative de l’architecture
type memoireDonnees_type is array(0 to 2 ** Md - 1) of signed(Wd - 1 downto 0);
signal memoireDonnees : memoireDonnees_type;
signal sortieMemoireDonnees : signed(Wd - 1 downto 0);
signal adresseMemoireDonnees : integer range 0 to 2 ** Md - 1;
signal lectureEcritureN : std_logic;
-- dans le corps de l’architecture
-- mémoire des données
process (CLK)
begin
if rising_edge(CLK) then
if lectureEcritureN = '0' then
memoireDonnees(adresseMemoireDonnees) <= B;
end if;
end if;
end process;
sortieMemoireDonnees <= memoireDonnees(adresseMemoireDonnees);
Exemple 5-10 – mémoire des données
Le code utilise deux paramètres définis par des énoncés generic. Le premier, Md, spécifie le nombre de
bits d’adresse de la mémoire. Le nombre de cellules correspondant peut facilement être calculé à partir du
nombre de bits d’adresse. Le deuxième, Wd, donne la largeur des cellules de mémoire en bits.
Il est important de vérifier la documentation du synthétiseur utilisé pour obtenir le type de mémoire désiré
selon la technologie ciblée. La description de l’Exemple 5-10 est inspirée du manuel de l’utilisateur du
synthétiseur XST de Xilinx pour utiliser de la mémoire distribuée sur les blocs de logique programmable
de la puce. La version 2007 du manuel spécifie 16 façons différentes de décrire des blocs de mémoire
vive, et chacune ne mène pas nécessairement à la même utilisation des ressources de la puce.
INF3500 : Conception et réalisation de systèmes numériques
75
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
5.5
Unités fonctionnelles
Dans un chemin des données, les unités fonctionnelles effectuent le traitement de l’information.
5.5.1
Unités arithmétiques
Une unité arithmétique effectue des opérations arithmétiques entre des opérandes sous le contrôle d’un
code d’opération. Les unités arithmétiques sont au cœur de tous les microprocesseurs.
L’Exemple 5-11 démontre une unité arithmétique à 7 opérations. Le port d’entrée ‘choix’, exprimé sur 3
bits, permet de choisir l’opération à effectuer. Deux des valeurs de ‘choix’ permettent d’observer les 8
bits les plus significatifs ou moins significatifs de la multiplication.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity unitearithmetique is
generic (
W : positive := 8 -- largeur des opérandes
);
port(
A, B : in signed(W - 1 downto 0); -- les opérandes
choix : in std_logic_vector(2 downto 0); -- le sélecteur d'opération
F : out signed(W - 1 downto 0) -- le résultat
);
end unitearithmetique;
architecture arch of unitearithmetique is
begin
process(A, B, choix)
variable t : signed(2 * W - 1 downto 0);
begin
t := A * B;
case to_integer(unsigned(choix)) is
when 0 => F <= A + B;
when 1 => F <= A - B;
when 2 => F <= A + B + 1;
when 3 => F <= A + 1;
when 4 => F <= abs(A);
when 5 => F <= -A;
when 6 => F <= t(2 * W - 1 downto W);
when 7 => F <= t(W - 1 downto 0);
when others => F <= (others => 'X');
end case;
end process;
end arch;
Exemple 5-11 – unité arithmétique
a. Support par les outils de synthèse
Les synthétiseurs de VHDL sur le marché reconnaissent les opérations arithmétiques d’addition, soustraction et multiplication et infèrent correctement des circuits combinatoires pour les implémenter. Les opérateurs correspondants sont ‘+’, ‘-’ et ‘*’. Les opérations de division, reste et modulo sont supportées
uniquement lorsque le deuxième opérande est une constante égale à une puissance de deux.
Ce support permet au concepteur d’élever de façon notable le niveau d’abstraction de modélisation de
circuits arithmétiques en évitant d’avoir à penser aux menus détails de leur implémentation. Cependant, il
INF3500 : Conception et réalisation de systèmes numériques
76
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
est utile de bien comprendre les complexités relatives de ces opérations de façon à pouvoir faire des choix
de conception éclairés.
b. Types utilisés
Lors de la synthèse d’un modèle VHDL, le type des opérandes sur lesquels on effectue une opération
arithmétique est de grande importance. Les possibilités sont énumérées ici.

Types signed et unsigned. Ces types sont définis dans le package normalisé numeric_std.
Leurs définitions sont montrées à l’Exemple 5-12. Ces types correspondent à des tableaux de valeurs
std_logic et sont bien supportés par les outils de synthèse. Le package numeric_std redéfinit
tous les opérateurs de VHDL pour ces deux types. Comme leurs noms l’indiquent, les types signed
et unsigned correspondent respectivement à des nombres signés et non signés.
type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;
type SIGNED is array (NATURAL range <>) of STD_LOGIC;
Exemple 5-12 – types signed et unsigned définis dans numeric_std

Type integer. Le type integer est bien supporté par les synthétiseurs pour les opérations arithmétiques. Son avantage est qu’il permet au concepteur de faire abstraction de la représentation de
quantités par un tableau de bits. Cependant, il est important de spécifier la gamme de valeurs possibles pour les objets de type integer de façon à contraindre les ressources matérielles utilisées
pour les représenter. En l’absence d’une telle spécification, les synthétiseurs allouent en général 32
bits, ce qui est souvent beaucoup trop. L’Exemple 5-13 démontre l’utilisation du mot réservé range.
signal compteur : integer range 0 to 255 := 0;
signal op1 : integer range -16 to 15 := 0;
Exemple 5-13 – objets de type integer avec contrainte de gamme de valeurs

Type real. En général, le type real n’est supporté par les synthétiseurs que pour les expressions à
valeur statique. Les opérations arithmétiques en point flottant nécessitent beaucoup plus de ressources
que les opérations en point fixes. La précision qu’elles offrent n’est pas requise pour la plupart des
applications. En date de avril 2008, des efforts importants ont été consacrés à la préparation de packages supportant les opérations arithmétiques en point flottant conformément à la norme IEEE 754.
Certaines librairies sont disponibles en ligne. Cependant, aucune norme officielle n’a encore été promulguée.

Type std_logic_vector. Le package std_logic_1164 définit ce type comme un tableau de
std_logic, effectivement des bits pouvant prendre des valeurs physiques discrètes. Cependant, le
package n’inclut pas de définitions pour les opérations arithmétiques sur ce type. Des packages populaires incluent de telles définitions, comme std_logic_signed et std_logic_unsigned de
la compagnie Synopsys. Cependant, ces packages ne sont pas normalisés et leur utilisation n’est donc
pas recommandée.
c. Différences entre l’interprétation des types signed et unsigned
Dans le package numeric_std, les opérateurs de VHDL sont redéfinis pour les types signed et
unsigned. Le type signed est interprété comme représentant un nombre en complément à deux, alors
que le type unsigned est interprété comme un nombre non signé. Cette différence est illustrée par
l’Exemple 5-14 où le même vecteur de bits est affecté à trois signaux de types différents.
INF3500 : Conception et réalisation de systèmes numériques
77
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
signal A : signed(3 downto 0);
signal B : unsigned(3 downto 0);
signal C : std_logic_vector(3 downto 0);
. . .
A <= "1100"; -- -4
B <= "1100"; -- +12
C <= "1100"; -- bits 1100
Exemple 5-14 – interprétation de signed et unsigned
Pour l’addition et la soustraction, l’utilisation du type signed force une extension du signe quand les
deux opérandes ne sont pas exprimés avec le même nombre de bits. Cette extension du signe est requise
pour garantir un résultat correct. Le principe est illustré par l’Exemple 5-15.
1100 (-4)
10 (-2)
1110 (-2 : incorrect)
1100 (-4)
+1110 (-2)
1010 (-6 : correct)
+
Exemple 5-15 – extension du signe lors de l’addition de nombres signés
5.5.2
Unités logiques
L’Exemple 5-16 démontre comment une unité logique peut être modélisée en VHDL.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity unitelogique is
generic (
W : positive := 8 -- largeur des opérandes
);
port(
A, B : in std_logic_vector(W - 1 downto 0); -- les opérandes
choix : in std_logic_vector(2 downto 0); -- le sélecteur d'opération
F : out std_logic_vector(W - 1 downto 0) -- le résultat
);
end unitelogique;
architecture arch of unitelogique is
begin
process(A, B, choix)
begin
case to_integer(unsigned(choix)) is
when 0 => F <= A and B;
when 1 => F <= A or B;
when 2 => F <= A nand B;
when 3 => F <= A nor B;
when 4 => F <= A xor B;
when 5 => F <= A xnor B;
when 6 => F <= not(A);
when 7 => F <= not(B);
when others => F <= (others => 'X');
end case;
end process;
end arch;
Exemple 5-16 – unité logique
INF3500 : Conception et réalisation de systèmes numériques
78
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
Les unités logiques effectuent une opération logique sur des opérandes sous le contrôle d’un signal externe. Elles sont au cœur de tout microprocesseur. Par exemple, on peut vouloir effectuer une des opérations ET, OU, OUX, ou NON-ET entre deux vecteurs de façon dynamique.
Le package std_logic_1164 redéfinit les opérateurs logiques and, nand, or, nor, xor, xnor et
not pour les objets de type std_logic et std_logic_vector. Le package numeric_std fait de
même pour les types unsigned et signed.
5.5.3
Comparateurs
Un comparateur permet de comparer les grandeurs relatives de deux valeurs et d’identifier leur égalité
éventuelle. Ce type de circuit est essentiel dans un microprocesseur pour pouvoir effectuer des branchements conditionnels.
Les opérateurs de VHDL pour la comparaison sont =, /=, <, <=, >, et >=. Dans chaque cas le résultat de
la comparaison est de type boolean. L’Exemple 5-17 illustre l’utilisation de ces opérateurs. Il faut bien
différencier l’utilisation du symbole ‘<=’ selon le contexte, puisqu’il signifie à la fois « plus petit ou
égal » et « assignation de valeur à un signal ».
Comme pour les opérations arithmétiques, le type des opérandes est critique et peut déterminer la valeur
de la comparaison. Cela est particulièrement vrai pour les types signed et unsigned.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity comparateur is
generic (
W : positive := 8 -- largeur des opérandes
);
port(
A, B : in signed(W - 1 downto 0);
eq, neq, gt, lt, ge, le : out std_logic
);
end comparateur;
architecture arch of comparateur is
begin
eq <= '1' when A = B else '0';
neq <= '1' when A /= B else '0';
gt <= '1' when A > B else '0';
lt <= '1' when A < B else '0';
ge <= '1' when A >= B else '0';
le <= '1' when A <= B else '0';
end arch;
Exemple 5-17 – comparateur
5.5.4
Compteurs
Comme son nom l’indique, un compteur compte le nombre d’occurrences d’un événement, comme par
exemple des coups d’horloge. Un compteur est habituellement composé d’un registre couplé à un circuit
combinatoire qui calcule la prochaine valeur du compte en fonction de sa valeur présente. Il y a plusieurs
types de compteurs. On distingue entre autres les compteurs à déferlement et les compteurs synchrones,
qui diffèrent dans leur implémentation matérielle. Dans un compteur synchrone, toutes les bascules du
INF3500 : Conception et réalisation de systèmes numériques
79
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
compteur partagent une horloge commune. Dans un compteur à déferlement, les sorties des bascules servent d’horloge aux bascules suivantes. Ce type de compteur n’est pas recommandé à cause des problèmes
de synchronisation avec d’autres composantes.
L’Exemple 5-18 illustre le modèle VHDL d’un compteur synchrone à deux directions et à chargement
parallèle.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.numeric_std.all;
entity compteurSynchrone is
generic (
W : integer := 4 -- nombre de bits du compteur
);
port(
reset : in STD_LOGIC;
CLK : in STD_LOGIC;
mode : in unsigned(1 downto 0);
D : in unsigned(W - 1 downto 0);
Q : out unsigned(W - 1 downto 0)
);
end compteurSynchrone;
architecture comportementale of compteurSynchrone is
begin
process (CLK, reset)
variable Qinterne : unsigned(W - 1 downto 0);
begin
if reset='0' then
Qinterne := (others => '0');
elsif CLK='1' and CLK'event then
case mode is
when "01" => Qinterne := Qinterne + 1;
when "10" => Qinterne := Qinterne - 1;
when "11" => Qinterne := D;
when others => Qinterne := Qinterne;
end case;
end if;
Q <= Qinterne;
end process;
end comportementale;
Exemple 5-18 – compteur synchrone à quatre modes
Les compteurs peuvent suivre différentes séquences selon l’application désirée :

Compteur binaire. Un compteur binaire suit une progression monotone : 000, 001, 010, 011, …, 101,
110, 111, 000, 001, etc. Un compteur binaire à n bits a 2n états différents.

Compteur modulo-n. Ce compteur est réinitialisé à zéro dès qu’une valeur spécifiée est atteinte.

Compteur BCD. Ce cas particulier d’un compteur modulo à quatre bits a comme séquence 0000,
0001, … 1000, 1001, 0000, 0001, …;

Compteur à anneau. Ce compteur utilise n bits pour n états différents. Une séquence type pour un
compteur à quatre bits serait 0001, 0010, 0100, 1000, 0001, 0010, etc. Le désavantage de ce compteur
est qu’il peut entrer dans une séquence d’états interdits si une erreur se produit. Il est cependant
simple à concevoir.
INF3500 : Conception et réalisation de systèmes numériques
80
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données

Compteur Johnson. Le compte pour ce type de compteur est particulier parce que tous les ‘1’ sont
placés en un seul groupe qui se déplace dans le compteur. Une séquence typique serait : 0000, 0001,
0011, 0111, 1111, 1110, 1100, 1000, 0000, 0001, etc. Comme le compteur à anneau, ce compteur
peut entrer dans une séquence d’états interdits. Il requiert n bits pour 2 × n états. Ce compteur est une
variante du compteur à anneau, où le bit le moins significatif est chargé avec l’inverse du bit le plus
significatif.

Compteur à séquence arbitraire. L’utilisateur détermine la séquence, comme par exemple 0, 3, 1, 4, 2,
6, 0, 3, 1, etc.
En plus de la séquence suivie, les compteurs peuvent être caractérisés par :
5.6

La valeur de réinitialisation (souvent 0).

La direction du compte (le haut, le bas ou les deux).

Le chargement parallèle d’une valeur de compte.

Une entrée ou une sortie sérielle.
Exercices
1. Consulter des ressources en ligne concernant le circuit ‘74LS138’.
a. Quelle est la fonction logique correspondante?
b. Quelles sont les entrées et les sorties?
c. Donner le code VHDL modélisant ce circuit.
2. Comparez le code VHDL d’un multiplexeur 2:1, écrit à l’aide d’un énoncé if-else, et celui d’un
loquet D.
3. Donner le code VHDL pour un encodeur à priorité à 4 entrées pour lequel les priorités sont, en ordre
croissant, D2, D1, D3, D0.
4. Considérer l’opération consistant à décaler les bits d’un nombre exprimé en complément à deux vers
la gauche ou vers la droite.
a. Quelles sont les opérations arithmétiques correspondantes?
b. Comment pourrait-on traiter les débordements vers la gauche ou vers la droite?
c. Quelles sont les opérateurs de VHDL utiles pour implémenter ces opérations?
d. Donner le code VHDL d’un décaleur polyvalent, avec une entrée pour le nombre et des entrées de
contrôle. Justifiez bien tous vos choix de design.
5. Donner un module VHDL qui accepte en entrée un nombre exprimé avec 6 bits ainsi qu’un facteur
exprimé avec 3 bits. La sortie doit être le produit du nombre et de son facteur. Utilisez uniquement les
opérations d’addition, soustraction et décalage. Votre circuit doit être robuste, c’est-à-dire qu’il doit
donner un résultat qui est toujours valide, ou bien avoir un signal de sortie indiquant la validité du résultat.
6. Expliquez le processus de synthèse du modèle de l’Exemple 5-2 pour n = 1. Montrez que vous obtenez le même circuit que celui donné à la Figure 5-3.
7. Expliquez le processus de synthèse du modèle de l’Exemple 5-3.
8. Expliquez pourquoi la description de l’Exemple 5-4 serait incorrecte si on inversait l’ordre des deux
énoncés à l’intérieur du processus.
INF3500 : Conception et réalisation de systèmes numériques
81
v. 2.5, juillet 2013
Chapitre 5 : Conception de chemins des données
9. Expliquez le processus de synthèse du modèle de l’Exemple 5-5.
10. La déclaration d’entité suivante en VHDL correspond à un circuit combinatoire qui accepte en entrée
un nombre de six bits et qui a une sortie pour indiquer si le nombre est divisible par sept. Donnez une
architecture pour cette entité.
library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;
entity multipleDeSept is
port (I : in unsigned(5 downto 0); F : out std_logic);
end multipleDeSept;
11. Donnez le modèle VHDL d’un registre pour lequel la valeur de réinitialisation est déterminée par un
énoncé generic dans la partie déclarative de l’entité. Vérifiez le fonctionnement du circuit par simulation.
12. Donnez le modèle VHDL d’un registre à décalage permettant d’effectuer une multiplication par 1, 2,
ou 4. Vérifiez le fonctionnement du circuit par simulation.
13. Proposez un circuit utilisant le registre à décalage de la question précédente pour effectuer une multiplication par 0, 1, 2, 3, 4, 5, 6 ou 7. N’utilisez pas l’opérateur de multiplication. Vérifiez le fonctionnement du circuit par simulation.
14. Donnez le modèle VHDL d’un compteur à 6 bits dont la sortie est croissante et est uniquement composée de nombres premiers. Vérifiez le fonctionnement du circuit par simulation.
15. Un compteur binaire peut être utilisé comme diviseur de fréquence d’horloge, si on considère que son
bit le plus significatif varie moins vite que son bit le moins significatif. Montrez la relation entre la
fréquence d’horloge appliquée au compteur et la fréquence à laquelle varie son bit le plus significatif,
en fonction du nombre de bits du compteur. Donnez la largeur de compteur nécessaire pour réduire
une fréquence d’horloge de 100 MHz à 1 Hz environ.
INF3500 : Conception et réalisation de systèmes numériques
82
v. 2.5, juillet 2013
Conception d’unités de contrôle
Chapitre 6
Au Chapitre 5, on a abordé le problème de la conception du chemin des données d’un processeur. Dans le
présent chapitre, on aborde le problème de la conception de son unité de contrôle.
6.1
Circuits séquentiels
Les circuits combinatoires permettent de réaliser une foule de fonctions utiles telles que la génération de
signaux de contrôle d’un système d’alarme en fonction de l’état de différents senseurs ou l’addition et la
soustraction de nombres binaires. Cependant, il serait impossible de réaliser des circuits dont la sortie
dépend des entrées précédentes ou des circuits qui doivent « se souvenir » d’un état particulier en utilisant
uniquement des composantes combinatoires. Un exemple simple est la mémoire d’une calculatrice pour
conserver un résultat qui doit être réutilisé.
Un circuit séquentiel comporte une partie combinatoire ainsi que des éléments à mémoire. Les éléments à
mémoire entreposent l’état présent du circuit. Le circuit combinatoire calcule le prochain état du système
ainsi que ses sorties. La Figure 6-1 illustre le modèle d’un circuit séquentiel de base.
circuit combinatoire
sorties
entrées
éléments à
mémoire
prochain état
état présent
horloge
Figure 6-1 – modèle d’un circuit séquentiel
On distingue dans un circuit séquentiel:

des éléments à mémoire, qui sont soit des loquets (latch) ou des bascules (flip-flop), qui conservent en
mémoire l’état présent du circuit;

un circuit combinatoire pour calculer le prochain état et les sorties;

une horloge pour synchroniser le circuit;

des entrées; et,

des sorties.
Il y a deux types de circuits séquentiels : les circuits de Moore et de Mealy.
Dans une machine de Moore, les sorties ne sont fonctions que de l’état présent.
Dans une machine de Mealy, les sorties sont fonctions de l’état présent ainsi que des entrées.
INF3500 : Conception et réalisation de systèmes numériques
83
v. 2.42, décembre 2009
Chapitre 6 : Conception d’unités de contrôle
La Figure 6-2 illustre un modèle général de circuit séquentiel avec des sorties de Moore et de Mealy.
circuit combinatoire
fonction de sortie (Moore)
sorties de Moore
entrées
fonction de sortie (Mealy)
éléments à mémoire
calcul du prochain état
sorties de Mealy
prochain état
état présent
horloge
Figure 6-2 – sorties de Moore et de Mealy
Analyse d’un circuit séquentiel synchrone
6.2
La procédure pour analyser un circuit séquentiel synchrone à partir d’un diagramme donné consiste à :
1. identifier les variables d’états;
2. écrire les équations d’états et les équations de sortie;
3. dresser le tableau d’états; et,
4. dessiner le diagramme d’états.
6.2.1
Variables et équations d’états
L’état d’un circuit séquentiel est la valeur de tous ses éléments à mémoire à un moment donné.
Dans un circuit séquentiel, un signal de sortie d’un élément à mémoire est une variable d’état du circuit.
Les équations d’état d’un circuit séquentiel déterminent la valeur des variables d’état du circuit en fonction de leurs valeurs présentes ainsi que des entrées du système. Les équations d’état sont aussi appelées
équations de transition.
6.2.2
Tableau d’états
Un tableau d’états (aussi appelé tableau de transitions d’états) est similaire à une table de vérité. Il comporte quatre sections : les états présents, les entrées, les états prochains, et les sorties.
Si on a m bascules et n entrées, le tableau a 2m + n rangées en forme générale.
En forme compacte, le tableau n’a que 2m rangées. On forme alors des colonnes pour couvrir les différents
cas des variables d’entrée.
INF3500 : Conception et réalisation de systèmes numériques
84
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
6.2.3
Diagrammes d’états
Toute l’information présente dans un tableau d’états peut être représentée sous forme graphique par un
diagramme d’états, et vice versa. Un diagramme d’états contient toute l’information d’un tableau d’états
mais facilite la compréhension du comportement du circuit. Dans un diagramme d’états :

les états sont identifiés par des cercles étiquetés de leur nom et/ou de leur code binaire associé;

les transitions entre les états sont identifiées par des flèches entre les cercles;

les conditions pour les transitions sont placées à côté des flèches de transition;

pour les machines de Moore (i.e. si les sorties ne dépendent que de l’état présent), la valeur des signaux de sortie est placée à l’intérieur des cercles; et,

pour les machines de Mealy (i.e. si les sorties dépendent de l’état présent et des entrées), la valeur des
signaux de sortie est placée à côté des flèches de transition  on les sépare des conditions de transition
par une barre oblique.
6.3
Description de machines à états en VHDL
6.3.1
Description à partir d’un schéma ou d’équations d’états
Ce type de description d’un circuit séquentiel en VHDL est adéquat quand on a déjà le circuit sous forme
de schéma et qu’on désire en modéliser le comportement. Il est aussi adéquat quand on a fait le travail de
conception et qu’on a obtenu les équations d’états et de sortie du circuit désiré.
Considérons le circuit numérique de la Figure 6-3. Un modèle de ce circuit peut être construit en VHDL
en inspectant le schéma et en décrivant sa structure ou sa fonctionnalité. Un tel modèle est montré à
l’Exemple 6-1.
D
Q
CLK
Q'
Z
X
D
Q
CLK
CLK
Q'
Figure 6-3 – exemple de circuit séquentiel
INF3500 : Conception et réalisation de systèmes numériques
85
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
library IEEE;
use IEEE.std_logic_1164.all;
entity cctsequentielex1 is
port (
reset : in STD_LOGIC;
CLK : in STD_LOGIC;
X : in STD_LOGIC;
Z : out STD_LOGIC
);
end cctsequentielex1;
architecture arch1 of cctsequentielex1 is
signal A : STD_LOGIC; -- bascule A (en haut)
signal B : STD_LOGIC; -- bascule B (en bas)
begin
process(CLK, reset) is
begin
if (reset = '0') then
A <= '0';
B <= '0';
elsif (rising_edge(CLK)) then
A <= A xor B;
B <= x or not(B);
end if;
end process;
-- signal de sortie
z <= not(A or B);
end arch1;
Exemple 6-1 – modèle VHDL du circuit de la Figure 6-3
Le modèle a la même forme fondamentale que l’Exemple 2-13 pour une bascule D avec réinitialisation
asynchrone, mais en combinant deux bascules à l’intérieur d’un même processus. Les équations pour les
valeurs futures des variables d’état A et B sont exprimées directement par des équations booléennes à
l’intérieur du processus. Un énoncé concurrent, à l’extérieur du processus, est utilisé pour spécifier la
valeur de la sortie Z en fonction des deux variables d’état.
Dans l’Exemple 6-1 on a rajouté un signal de réinitialisation des variables d’état A et B, ce qui n’est pas
montré à la Figure 6-3. En règle générale, il faut toujours inclure un signal de réinitialisation aux circuits
séquentiels, spécialement ceux qui doivent être implémentés.
6.3.2
Description à partir d’un diagramme d’états
VHDL permet d’utiliser une approche très puissante pour décrire un circuit séquentiel directement à partir
du diagramme d’états sans avoir à passer par les équations d’états. Considérons le diagramme d’états de
la Figure 6-4, qui correspond au circuit de la Figure 6-3.
On distingue les quatre états, identifiés dans les bulles par les codes 0 à 3. Sous ces identificateurs on
trouve la valeur de sortie quand la machine est dans un état en particulier. Comme la valeur de sortie de
ne dépend que de l’état et pas de l’entrée, ce diagramme correspond à une machine de Moore. Les transitions sont indiquées par des flèches avec une valeur associée; la transition se produit si l’entrée est égale à
cette valeur. Le tiret ‘-‘ indique que la transition est toujours prise, que l’entrée soit égale à 0 ou 1. L’état
lors de la réinitialisation est indiqué par une flèche spéciale.
INF3500 : Conception et réalisation de systèmes numériques
86
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
-
reset
(état
initial)
État 0
Sortie: 1
État 1
Sortie: 0
1
0
0
1
État 3
Sortie: 0
État 2
Sortie: 0
-
Figure 6-4 – diagramme d’états correspondant au circuit de la Figure 6-3
Une version de code VHDL correspondant à ce diagramme d’états est donnée à l’Exemple 6-2, sous la
forme d’une deuxième architecture pour l’entité cctsequentielex1 de l’Exemple 6-1.
architecture arch2 of cctsequentielex1 is
type type_etat is range 0 to 3;
signal etat : type_etat := 0;
begin
process(CLK, reset) is
begin
if (reset = '0') then
etat <= 0;
elsif (rising_edge(CLK)) then
case etat is
when 0 =>
etat <= 1;
when 1 =>
if x = '0' then etat <= 2; else etat <= 3; end if;
when 2 =>
etat <= 3;
when 3 =>
if x = '0' then etat <= 0; else etat <= 1; end if;
end case;
end if;
end process;
z <= '1' when etat = 0 else '0';
-- signal de sortie
end arch2;
Exemple 6-2 – modèle VHDL du diagramme d’états de la Figure 6-4
L’état présent est gardé en mémoire par un signal, etat, dont le type est défini comme étant un entier
pouvant prendre les valeurs 0, 1, 2 et 3. Une définition de type permet de restreindre les valeurs possibles,
ce qui augmente grandement la robustesse du code.
Un processus permet de modéliser la mémorisation de l’état. Une réinitialisation asynchrone est spécifiée.
Un énoncé case couvre les quatre possibilités de la valeur de l’état. Dans chaque cas, on donne la valeur
de l’état prochain selon la valeur de l’entrée s’il y a lieu. Un énoncé concurrent à l’extérieur du processus
spécifie la valeur de la sortie en fonction de l’état.
Cette description de la machine à états est beaucoup plus lisible, robuste et facile à maintenir que celle de
l’Exemple 6-1. De plus, comme on débute habituellement le processus de conception à partir d’un diagramme d’états, il est beaucoup plus efficace de passer directement à un modèle VHDL de la forme de
l’Exemple 6-2 que de suivre la procédure plus traditionnelle consistant à obtenir les équations d’état.
INF3500 : Conception et réalisation de systèmes numériques
87
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
6.3.3
Encodage des états
Considérons le diagramme d’états de la Figure 6-5. Dans cette machine, les états sont identifiés par les
symboles S1, S2, S3 et S4. Dans le code VHDL correspondant, on pourrait les représenter par des entiers,
par exemple 1, 2, 3 et 4. Cependant, il est plus pratique de conserver les mêmes identificateurs que dans le
diagramme d’états. Selon le cas, on pourrait par exemple utiliser des identificateurs comme « départ »,
« fin » ou « go ». En VHDL, il est aisé de fonctionner ainsi en utilisant un type énumératif pour la variable d’état, ce qui permet de conserver un niveau d’abstraction élevé pour la description de la machine.
Ceci est démontré à l’Exemple 6-3 par la définition d’un nouveau type, puis par la déclaration d’un signal
de ce type.
X’
reset
S1
Sortie = 1
S3
Sortie = 0
S2
Sortie = 1
S4
Sortie = 0
X
Figure 6-5 – une autre machine à états
type type_etat is (S1, S2, S3, S4);
signal etat : type_etat := S1;
Exemple 6-3 – type énumératif pour la variable d’état
L’utilisation d’un type énumératif pour une variable d’état évite au concepteur d’avoir à se soucier de
l’encodage final de la variable d’état tel que déterminé par le synthétiseur. On peut laisser le synthétiseur
choisir l’encodage le plus efficace selon des contraintes désirées (vitesse, complexité ou puissance). On
peut aussi parfois imposer au synthétiseur un style particulier tel que le code Gray, le code Johnson ou un
code « one hot ». Il faut consulter la documentation du synthétiseur pour savoir comment activer ces différents modes.
De façon contraire, on veut parfois spécifier explicitement l’encodage utilisé pour les états. Ceci peut être
fait directement dans le code VHDL grâce à l’utilisation de l’attribut enum_encoding. Ceci est démontré par l’Exemple 6-4. À nouveau, il est essentiel de consulter la documentation du synthétiseur.
type type_etat is (S1, S2, S3, S4);
attribute enum_encoding : string;
attribute enum_encoding of type_etat : type is "00 10 11 01";
signal etat : type_etat := S1;
Exemple 6-4 – spécifier explicitement l’encodage de la variable d’état
INF3500 : Conception et réalisation de systèmes numériques
88
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
6.3.4
Styles de description de machines à états en VHDL
La Figure 6-2 illustre les trois parties d’une machine à états :

les éléments à mémoire qui conservent l’état présent de la machine;

un circuit combinatoire qui calcule le prochain état; et,

un circuit combinatoire qui calcule les sorties de Moore et de Mealy.
Pour décrire une machine à états en VHDL, il y a donc plusieurs styles de description possibles, selon la
répartition des trois parties de la machine sur un ou plusieurs processus. Chaque style correspond à un
point de vue différent de la machine à états. Les styles de description les plus usités sont :

Un seul processus (Exemple 6-5). Les trois parties de la machine sont décrites dans un seul processus.
Cela résulte habituellement en l’inférence de registres pour les sorties, et il faut faire attention pour
bien spécifier leur synchronisation dans le code. En fait, il faut spécifier la sortie du prochain état
étant donnés un état et une entrée présentes. Si plusieurs conditions résultent en un état donné, il faut
spécifier la sortie de Moore de cet état à chaque fois.
architecture unprocessus of cctsequentielex2 is
type type_etat is (S1, S2, S3, S4);
signal etat : type_etat := S1;
begin
process(CLK, reset) is
begin
if (reset = '0') then
etat <= S1;
sortie <= '1';
elsif (rising_edge(CLK)) then
case etat is
when S1 =>
if x = '0' then
etat <= S3;
sortie <= '0';
else
etat <= S2;
sortie <= '1';
end if;
when S2 | S3 =>
etat <= S4;
sortie <= '0';
when S4 =>
etat <= S1;
sortie <= '1';
end case;
end if;
end process;
end unprocessus;
Exemple 6-5 – machine à états avec un seul processus

Deux processus (Exemple 6-6). Un processus est utilisé pour le calcul et l’entreposage de l’état, et un
deuxième processus est utilisé pour les sorties. Le deuxième processus peut être remplacé par des
énoncés concurrents. Cette approche est démontrée aussi à l’Exemple 6-2, où le processus pour la sortie est remplacé par un énoncé concurrent. Cette approche offre un bon compromis entre la flexibilité
et la lisibilité du code.
INF3500 : Conception et réalisation de systèmes numériques
89
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
architecture deuxprocessus of cctsequentielex2 is
type type_etat is (S1, S2, S3, S4);
signal etat : type_etat := S1;
begin
process(CLK, reset) is
begin
if (reset = '0') then
etat <= S1;
elsif (rising_edge(CLK)) then
case etat is
when S1 =>
if x = '0' then
etat <= S3;
else
etat <= S2;
end if;
when S2 | S3 =>
etat <= S4;
when S4 =>
etat <= S1;
end case;
end if;
end process;
process(etat)
begin
case etat is
when S1 | S2 => sortie <= '1';
when S3 | S4 => sortie <= '0';
end case;
end process;
end deuxprocessus;
Exemple 6-6 – machine à états avec deux processus

Trois processus (Exemple 6-7) Cette approche a l’avantage de correspondre exactement au modèle de
la Figure 6-2. Le code est très lisible, mais est moins compact que la version à deux processus. On
observe que la liste de sensibilité du processus qui calcule le prochain état inclut le signal qui entrepose l’état courant ainsi que toutes les entrées. Le même principe s’applique au processus qui calcule
les sorties, bien que dans l’Exemple 6-7 ce soit une machine de Moore dont la sortie ne dépend pas
des entrées.
Cette variété d’options illustre à nouveau la très grande richesse de VHDL. Cette richesse cause cependant beaucoup de difficultés parce qu’il n’existe pas une norme unique pour la description de machines à
états. Il est donc plus difficile de concevoir un synthétiseur qui puisse reconnaître de façon satisfaisante
les intentions du concepteur. À nouveau, il est nécessaire de consulter le manuel d’utilisation du synthétiseur utilisé afin de connaître les styles d’encodage de machines à états reconnus.
INF3500 : Conception et réalisation de systèmes numériques
90
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
architecture troisprocessus of cctsequentielex2 is
type type_etat is (S1, S2, S3, S4);
signal etat : type_etat := S1;
signal etat_prochain : type_etat := S1;
begin
-- processus pour garder l'état actuel en mémoire
process(CLK, reset) is
begin
if (reset = '0') then
etat <= S1;
elsif (rising_edge(CLK)) then
etat <= etat_prochain;
end if;
end process;
-- processus pour le calcul du prochain état
process(etat, x) is
begin
case etat is
when S1 =>
if x = '0' then
etat_prochain <= S3;
else
etat_prochain <= S2;
end if;
when S2 | S3 =>
etat_prochain <= S4;
when S4 =>
etat_prochain<= S1;
end case;
end process;
-- processus pour les sorties
process(etat)
begin
case etat is
when S1 | S2 => sortie <= '1';
when S3 | S4 => sortie <= '0';
end case;
end process;
end troisprocessus;
Exemple 6-7 – machine à états avec trois processus
6.4
Conception de machines à états
6.4.1
Principes de base
La conception d’une machine à états, comme toutes les activités de design, est un processus créatif. Elle
est similaire à la description d’un algorithme dans un langage de programmation. Voici certaines caractéristiques similaires entre les deux :

Le processus débute avec une description la plus précise possible de la relation désirée entre les entrées et les sorties du système, sans nécessairement connaître les détails internes de l’implémentation.

Pendant le processus de design, il est souvent nécessaire de faire des choix entre différentes façons de
faire, et à chaque fois en faisant un compromis entre des contraintes qui ne peuvent toutes être satisfaites simultanément. Ces contraintes peuvent inclure entre autres la performance, la précision, la
INF3500 : Conception et réalisation de systèmes numériques
91
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
complexité, la lisibilité, la testabilité et la consommation de puissance. Le choix entre les différentes
options est parfois fait de façon arbitraire.

Il faut parfois essayer deux ou trois version d’une même section du problème avant de faire un choix.

Des cas spéciaux doivent être considérés séparément.

Pendant le processus de conception, on réalise souvent que la spécification est incomplète, ambigüe,
pas optimale ou mal comprise.

Le système une fois conçu se comporte exactement tel qu’il a été décrit, mais pas nécessairement
comme on voudrait qu’il se comporte.

En général, rien ne marche la première fois. Il faut passer à travers plusieurs itérations avant de converger vers une solution acceptable.

Il est essentiel de documenter minutieusement le design à toutes les étapes de la conception.
6.4.2
Procédure traditionnelle
La procédure traditionnelle pour concevoir un circuit séquentiel synchrone est grosso modo l’inverse de la
procédure d’analyse décrite à la section 6.2. Cependant, alors que l’analyse n’implique pas le choix
d’options, lors de la conception d’une machine état il faut toujours faire des compromis. La procédure
traditionnelle peut être résumée aux étapes suivantes :
1. bâtir un diagramme d’états à partir des données du problème;
2. bâtir le tableau d’états à partir du diagramme d’états, en identifiant les états par des symboles;
3. réduire le nombre d’états nécessaires en éliminant les états équivalents;
4. assigner un code binaire à chaque état, et ajouter cette information au tableau d’état;
5. à partir du tableau d’état complet, obtenir les équations booléennes d’entrée des bascules du type
choisi ainsi que les équations booléennes des sorties du système, en simplifiant si possible;
6. donner le diagramme et/ou construire le circuit; et,
7. vérifier, vérifier, vérifier.
6.4.3
Procédure avec un langage de description matérielle
VHDL permet de décrire une machines à états à un niveau élevé d’abstraction, avec un style semblable à
celui d’un langage de programmation. Il est donc inutile de bâtir un tableau d’état, et d’obtenir ou simplifier les équations d’états et de sortie. L’assignation d’un code binaire aux états devrait en général être
laissée à l’outil de synthèse, tel que décrit à la section 6.3.3. Le diagramme ou circuit est quant à lui généré automatiquement par l’outil de synthèse. La réduction des états peut parfois être nécessaire pour une
machine complexe, et on ne peut se passer de la vérification.
La description d’une machine à états directement en VHDL a plusieurs avantages, pour autant qu’on utilise un style d’encodage formel comme l’un de ceux décrits à la section 6.3.4. Il est alors facile de partager la spécification de la machine dans une équipe et sa documentation en est grandement simplifiée.
Une méthodologie de conception populaire des années 1970 s’appuyait sur le principe de la machine à
états algorithmique (Algorithmic State Machine – ASM). Un diagramme ASM ressemble grandement à un
organigramme utilisé pour décrire un algorithme. L’utilisation de diagrammes ASM a été pratiquement
éliminée par l’avènement des HDL.
INF3500 : Conception et réalisation de systèmes numériques
92
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
6.4.4
Bâtir le diagramme d’états
La première étape de conception consiste à bâtir un diagramme d’états. Bien qu’il soit possible de dériver
le code VHDL décrivant la machine à états directement à partir des données du problème, la représentation graphique offerte par un diagramme d’états est très avantageuse. Certains outils de conception produisent même automatiquement du code VHDL à partir d’un diagramme d’états.
Les principes suivants peuvent grandement aider à obtenir le diagramme d’états.
1. À partir des données du problème, simuler certaines combinaisons d’entrée pour bien comprendre la
nature du problème.
2. Commencer par construire un diagramme partiel menant à une sortie désirée du système.
3. Ajouter au diagramme les autres chemins menant aux sorties désirées du système.
4. Vérifier le diagramme pour éviter les états équivalents. Deux états sont équivalents s’ils mènent aux
mêmes prochains états et ont les mêmes sorties pour les mêmes entrées.
5. Compléter le diagramme en ajoutant des transitions pour toutes les entrées possibles à partir de
chaque état.
6. Identifier toute condition où le circuit doit être réinitialisé à un état de départ, et annoter le diagramme
avec cette information.
7. Vérifier le diagramme en appliquant des combinaisons d’entrées représentatives.
6.4.5
Décomposition de machines à états
Comme pour les circuits combinatoires, les circuits séquentiels peuvent aussi être décomposés en blocs
simples. La décomposition peut suivre une approche hiérarchique. Les différentes sous-machines à états
doivent pouvoir communiquer entre elles à l’aide de signaux de contrôle et de données. La Figure 6-6
illustre un modèle de décomposition hiérarchique pour une machine à états.
Sousmachine #1
Go1
Machine
principale
Fini1
sorties
entrées
Go2
Fini2
Sousmachine #2
Figure 6-6 – décomposition hiérarchique d’une machine à états
Une machine principale reçoit les entrées et sorties principales. Elle communique avec des sous-machines
par l’entremise de signaux de contrôle, qui sont des entrées et sorties de ces sous-machines. Les sousmachines peuvent aussi recevoir des entrées de l’extérieur et produire des sorties pour l’extérieur. Une
sous-machine peut elle-même être décomposée en plusieurs autres machines.
INF3500 : Conception et réalisation de systèmes numériques
93
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
La décomposition d’une machine à états en machine principale et en sous-machine permet d’augmenter
significativement le nombre total d’états possibles tout en gardant le diagramme global assez simple. En
effet, le nombre total d’états dans lequel la machine peut se trouver est égal au produit du nombre d’états
de chacune des sous-machines qui la compose.
6.4.6
Circuits combinatoires itératifs et circuits séquentiels
Un circuit combinatoire itératif est un circuit composé de n modules identiques connectés en cascade. Les
modules ont des entrées principales EP, des sorties principales SP, des entrées de connexion en cascade
EC et des sorties de connexion en cascade SC. Le modèle d’un circuit combinatoire itératif est montré à la
Figure 6-7.
EP0
EP1
EP
C-1
EC
EP
C0
module
SC
Epn-1
EC
module
C1
EP
Cn-2
SC
EC
Cn-1
module
SP
SP
SP
SP0
SP1
SPn-1
SC
Figure 6-7 – modèle d’un circuit combinatoire itératif
Un exemple de circuit itératif est un circuit qui compare l’égalité de deux nombres de n bits. Un module
de base pour un tel circuit est montré à la Figure 6-8. Le module accepte deux bits X et Y et les compare à
l’aide d’une porte NON-OU-exclusif, dont la sortie est 0 s’ils sont différents et 1 s’ils sont identiques. Le
module accepte aussi une entrée indiquant si toutes les comparaisons précédentes ont révélé que les entrées étaient identiques, EGe. La sortie EGs donne le résultat de la comparaison globale à ce point. Le
module n’a pas de sortie principale.
X Y
comp1
EGs
EGe
Figure 6-8 – module de comparaison itératif à un bit
Le circuit complet pour un comparateur itératif à n bits est montré à la Figure 6-9.
1
X0
Y0
X1
Y1
Xn-1
Yn-1
X
Y
X
Y
X
Y
EGe comp1 EGs
EGe comp1 EGs
Egalite
EGe comp1 EGs
Figure 6-9 – comparateur itératif à n bit
INF3500 : Conception et réalisation de systèmes numériques
94
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
L’avantage d’un circuit combinatoire itératif est la simplicité avec laquelle il peut être décrit, ainsi que la
simplicité relative du circuit final. Le désavantage principal vient du fait que le délai est proportionnel au
nombre de modules dans la cascade.
Dans un circuit combinatoire itératif, les entrées et les sorties principales sont disponibles en format parallèle. Si les entrées sont disponibles en format série et que l’on est prêt à accepter les sorties principales en
format série aussi, alors il existe une version séquentielle du même circuit qui est très simple et qui nécessite très peu de matériel. En fait, il s’agit d’utiliser un module unique ainsi qu’un nombre de bascules égal
au nombre d’entrées/sorties de connexion en cascade.
La forme séquentielle série du circuit comparateur combinatoire itératif est montrée à la Figure 6-10. La
bascule permet effectivement de remplacer toute la chaîne de modules du circuit. Les entrées X et Y sont
des entrées série synchronisées avec le signal d’horloge CLK. L’entrée init doit être activée au début
pour fixer le contenu de la bascule à la valeur 1, tel que montré à la Figure 6-9.
X Y
comp1
D
Q
CLK
CLK
set
init
Figure 6-10 – comparateur séquentiel série à n bit
6.5
Retour sur la conception de processeurs et l’approche RTL
On a brièvement discuté de l’approche RTL (Register Transfer Level) à la section 5.2. Dans l’approche
RTL, le concepteur spécifie les registres du processeur, les transferts de données entre ces registres, les
opérations à effectuer et les signaux de contrôle pour gérer ces activités.
L’approche RTL peut être décomposée en quatre étapes :
1. Analyse détaillée du problème afin de bien comprendre le flot des données à travers le processeur.
2. Conception du chemin des données et identification des signaux de contrôle et d’état.
3. Conception de l’unité de contrôle du processeur à l’aide d’une machine à états générant des signaux
de contrôle.
4. Vérification que le processeur résultant rencontre les spécifications.
Pour concevoir l’unité de contrôle du processeur, il faut créer un diagramme d’états qui décrit bien le
comportement attendu et qui correspond aux spécifications. À l’étape 2, on a créé un chemin des données
qui illustre les calculs à faire par le processeur. À l’étape 3, on spécifie dans quel ordre les calculs doivent
être faits. On peut raffiner le design en alternant entre les étapes 2 et 3.
INF3500 : Conception et réalisation de systèmes numériques
95
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
6.6
Exemple de processeur à usage spécifique: multiplicateur série
6.6.1
Révision de l’algorithme
Un multiplicateur série effectue la multiplication entre deux nombres comme on la calcule à la main. Par
exemple, la multiplication binaire entre les nombres 13 (11012) et 6 (01102) pourrait s’effectuer tel que
montré à la Figure 6-11. Le nombre 13 est appelé ici le multiplicande, et le nombre 6 est appelé le facteur.
1101
 0110
0000
 0000
00000
1101
 0110
00000
 11010
011010
1101
 0110
011010
 110100
1001110
1101
 0110
1001110
 0000000
01001110
Figure 6-11 – processus de multiplication habituel
La multiplication s’effectue en autant d’étape que le nombre de bits du multiplicateur (4 dans ce cas-ci).
À chaque étape, on détermine s’il faut additionner ou non la valeur du multiplicande à un accumulateur
dont la valeur initiale est zéro. À chaque étape, on considère un bit du facteur. Si c’est un 1, on additionne
la valeur du multiplicande. Si c’est un zéro, on ne fait rien. La somme résultante dans l’accumulateur est
reportée à l’étape suivante. La valeur à ajouter est décalée vers la gauche d’une position à chaque étape.
Chaque étape est effectivement séparable en deux micro-opérations : l’addition conditionnelle puis le
décalage en prévision de la prochaine addition.
On observe aussi que l’addition génère toujours un bit supplémentaire : additionner deux nombres de 4
bits donne une somme de 5 bits; additionner deux nombres de 5 bits donne une somme de 6 bits; etc.
En observant bien le processus de la Figure 6-11, on réalise que l’addition se fait toujours sur quatre bits.
On constate aussi qu’au lieu de décaler le multiplicande vers la gauche, on peut décaler l’accumulateur
vers la droite. Cette approche est montrée à la Figure 6-12. Du point de vue du matériel, cette approche
est un peu plus simple. Dans la figure, un point a été ajouté uniquement afin de souligner l’alignement des
termes. De plus, le facteur est aussi décalé vers la droite afin de toujours placer le bit qui contrôle
l’addition (montré [entre crochets] dans la figure) en position la moins significative.
1101.
 0110.
1101.
 0011.
0000.
 0000.
00000.
 0000.0
0000.0
 1101.
01101.0
 0110.10
1101.
 0001.
1101.
 0000.
0110.10
 1101.
10011.10
 1001.110
1001.110
 0000.
01001.110
 0100.1110
Figure 6-12 – processus de multiplication modifié
6.6.2
Ports d’entrée et de sortie
On va considérer un multiplicateur série avec six ports d’entrée et deux ports de sortie. La largeur des
opérandes est spécifiée par un paramètre, W.
En plus d’un signal d’horloge et de réinitialisation, le multiplicateur a besoin d’un signal de contrôle pour
démarrer le calcul, go. Afin de charger le multiplicande et le facteur, un seul port de données est utilisé,
mais avec deux signaux de contrôle, chargeA et chargeB, pour charger chacune une des deux opérandes à la fois (ou, exceptionnellement, une seule valeur pour les deux opérandes).
INF3500 : Conception et réalisation de systèmes numériques
96
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
Le multiplicateur a deux ports de sortie. Le port F donne le résultat de la multiplication. Le port fini est
un signal de contrôle indiquant que la valeur donnée sur le port F est valide, et que le multiplicateur est
prêt à accepter de nouveaux opérandes en entrée et à effectuer un nouveau calcul.
Le code VHDL pour la déclaration d’une entité respectant ces spécifications est donné à l’Exemple 6-8.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity multiplicateur is
generic (
W : integer := 4 -- nombre de bits des opérandes
);
port(
reset : in std_logic;
CLK : in std_logic;
go : in std_logic;
entree : in unsigned(W - 1 downto 0);
chargeA : in std_logic;
chargeB : in std_logic;
F : out unsigned(2 * W - 1 downto 0);
fini : out std_logic
);
end multiplicateur;
Exemple 6-8 – interface du multiplicateur série avec le monde extérieur
6.6.3
Chemin des données
En supposant que le multiplicande et le facteur soient exprimés sur W bits, on peut identifier les composantes suivantes pour le chemin des données du multiplicateur:

un registre de W bits à chargement parallèle pour entreposer le multiplicande;

un registre de W bits à chargement parallèle et à décalage vers la droite pour entreposer le facteur;

un registre de 2 × W + 1 bits à décalage vers la droite et à réinitialisation pour conserver la somme
cumulative; et,

un additionneur à deux opérandes de W bits (avec une somme de W + 1 bits).
Le chemin des données correspondant est montré à la Figure 6-13 avec les différents signaux de contrôle
indiqués. Les noms des signaux de contrôle sont explicites quant à leur sens. Le code VHDL correspondant à ce chemin des données est présenté à l’Exemple 6-9.
On suppose qu’un signal unique, entree, est utilisé pour charger le multiplicande et le facteur. Ce sont
les deux signaux de contrôle, chargeMultiplicande et chargeFacteur qui permettent de choisir
lequel des deux registres est chargé. Il serait possible bien sûr de charger les deux registres simultanément
avec une valeur unique. Le signal entree est un port d’entrée de l’entité. Les signaux
chargeMuliplicande et chargeFacteur sont des signaux dérivés de ports d’entrée; en effet, on
ne doit pas charger une nouvelle valeur pendant que les calculs sont lancés.
Le paramètre W, déclaré par un énoncé generic de l’entité, représente la largeur des opérandes. Le produit est donc exprimé avec 2 × W bits. Le registre qui contient le produit est déclaré ici avec un bit de plus
pour accommoder la sortie de l’additionneur. Dans la Figure 6-13, on indique le paramètre W sur les bus,
mais le dessin suppose que W est égal à 4.
INF3500 : Conception et réalisation de systèmes numériques
97
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
/
W
entree
chargeMultiplicande
chargeFacteur
decaleFacteur
multiplicande
clk
facteur
clk
/W
facteur(0)
additioneur
/W+1
chargeProduit
decaleProduit
initProduit
produit
clk
/
W
Figure 6-13 – chemin des données pour multiplicateur série – diagramme
cheminDonnees : process (clk)
begin
if rising_edge(clk) then
-- registre du multiplicande
if chargeMultiplicande = '1' then
multiplicande <= entree;
end if;
-- registre du facteur
if chargeFacteur = '1' then
facteur <= entree;
elsif decaleFacteur = '1' then
facteur <= shift_right(facteur, 1);
end if;
-- registre du produit
if initProduit = '1' then
produit <= (others => '0');
else
if chargeProduit = '1' then
produit(2 * W downto W) <= produit(2 * W downto W) + multiplicande;
elsif decaleProduit = '1' then
produit <= shift_right(produit, 1);
end if;
end if;
end if;
end process;
Exemple 6-9 – chemin des données pour multiplicateur série – code VHDL
INF3500 : Conception et réalisation de systèmes numériques
98
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
Un seul processus permet de décrire les trois registres simultanément. La description est conforme à celles
de l’Exemple 5-7 et de l’Exemple 5-8, mais simplifiée. Le registre du multiplicande n’inclut pas de réinitialisation. Le décalage conditionnel est plus simple parce qu’il n’inclut pas de bit sériel en entrée et qu’il
ne s’effectue que dans une direction. Le registre du produit est le plus complexe parce qu’il inclut les trois
opérations d’initialisation, chargement et décalage.
6.6.4
Unité de contrôle : machine à états
On peut représenter le processus de multiplication à l’aide du diagramme d’états montré à la Figure 6-14.
go
addition
fini <= ‘0’
attente
compteur <= W – 1
fini <= ‘1’
compteur /= 0
compteur = 0
reset
décalage
compteur <=
compteur – 1
fini <= ‘0’
Figure 6-14 – machine à états pour le multiplicateur série
La machine à états a trois états : attente, addition et décalage. Le diagramme d’états inclut les noms des
états ainsi que les signaux de contrôle en entrée et en sortie du processeur. La machine comporte un
compteur à W états, correspondant au nombre de bits du facteur. La machine débute dans l’état attente
lors de l’initialisation, et y reste tant que le signal ‘go’ est égal à 0. Ce signal est un port d’entrée du processeur. Quand ‘go’ est égal à ‘1’, la machine passe à l’état addition, dans lequel l’addition du multiplicande s’effectue si le bit le moins significatif du facteur est égal à ‘1’. La machine passe à l’état décalage,
dans lequel le compteur est décrémenté et les registres du produit et du facteur sont décalés d’un bit vers
la droite. Si le compteur est égal à 0 (avant la décrémentation), la machine passe à l’état attente et le signal ‘fini’ est activé à ‘1’, indiquant que la valeur du produit est maintenant valide.
6.6.5
Unité de contrôle : signaux et code VHDL
L’unité de contrôle doit implémenter la machine à états montrée à la Figure 6-14. Elle doit surtout générer
les signaux de contrôle identifiés à la Figure 6-13 en fonction de l’état de la machine et des entrées. Le
Tableau 6-1 résume les signaux de contrôle et les conditions nécessaires pour que chacun soit activé.
Les signaux chargeA et chargeB sont des ports d’entrée du processeur, contrôlés par le dispositif qui
requiert les services du multiplicateur.
L’Exemple 6-10 donne le code VHDL pour l’unité de contrôle du processeur. La description de l’unité de
contrôle comporte deux parties : un processus pour la machine à états et un groupe d’énoncés concurrents
pour les signaux de sortie et de contrôle. Les signaux de contrôle et le signal qui contient l’état doivent
être déclarés dans la partie déclarative de l’architecture afin d’être visibles dans toute celle-ci. Il faut se
INF3500 : Conception et réalisation de systèmes numériques
99
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
méfier en décrivant le processeur en VHDL afin de ne pas créer des bascules sans les désirer, ce qui affecterait la synchronisation de la machine.
signal de contrôle du chemin des données
condition pour activation
chargeMultiplicande
attente ET chargeA
chargeFacteur
attente ET chargeB
decaleFacteur
décalage
chargeProduit
addition ET facteur(0)
decaleProduit
décalage
initProduit
attente ET go
Tableau 6-1 – détails de l’unité de contrôle – multiplicateur
-- machine a états de l'unité de contrôle
controle : process (CLK, reset)
begin
if rising_edge(CLK) then
if reset = '1' then
etat <= attente;
else
case etat is
when attente =>
compteur <= compteurmax;
if go = '1' then
etat <= addition;
else
etat <= attente;
end if;
when addition =>
etat <= decalage;
when decalage =>
if (compteur = 0) then
etat <= attente;
else
etat <= addition;
compteur <= compteur - 1;
end if;
when others =>
etat <= attente;
end case;
end if;
end if;
end process;
-- signaux de sortie
F <= produit(2 * W - 1 downto 0);
fini <= '1' when etat = attente else '0';
-- signaux de controle
chargeMultiplicande <= '1' when etat = attente and chargeA = '1' else '0';
chargeFacteur <= '1' when etat = attente and chargeB = '1' else '0';
decaleFacteur <= '1' when etat = decalage else '0';
chargeProduit <= '1' when etat = addition and facteur(0) = '1' else '0';
decaleProduit <= '1' when etat = decalage else '0';
initProduit <= '1' when etat = attente and go = '1' else '0';
Exemple 6-10 – unité de contrôle pour multiplicateur série - VHDL
INF3500 : Conception et réalisation de systèmes numériques
100
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
6.6.6
Description combinée en VHDL
Le code VHDL montré à l’Exemple 6-9 et l’Exemple 6-10 représente fidèlement la description du multiplicateur conçu avec une approche RTL. En particulier, tous les signaux de contrôle sont explicitement
indiqués dans le code. Cependant, il est possible d’obtenir le même comportement avec une description
plus simple et plus claire. Une telle description est montrée à l’Exemple 6-11.
On dit que le code de l’Exemple 6-11 contient des signaux de contrôle implicites (plutôt qu’explicites),
c'est-à-dire qu’ils sont présents uniquement par la nature de la description du fonctionnement du circuit.
Par exemple, pour initialiser le registre de produit, le signal de contrôle initProduit devrait être
etat = attente and go = ‘1’. Cependant, on peut obtenir le même effet directement dans
l’énoncé case pour le choix correspondant à l’état d’attente, avec un énoncé if sur le signal go. On
observe le même principe pour le contrôle des autres registres.
6.7
Exemple : joueur de blackjack
6.7.1
Description du jeu
Le blackjack est un jeu de cartes très populaire dans les casinos. La partie oppose plusieurs joueurs à un
croupier qui joue pour le compte de la banque. Le but du jeu est d’accumuler plus de points que la banque
sans dépasser 21.
Les cartes ont les valeurs suivantes :

les cartes numérotées ont leur propre valeur (2 à 10);

les figures valent 10; et,

l’as peut valoir 1 ou 11, selon ce qui est le plus avantageux – une main contenant un as qui peut prendre une des deux valeurs est dite ‘facile’.
Le croupier distribue deux cartes visibles à chaque joueur, puis se donne une carte visible et une carte
cachée. Chaque joueur peut alors tirer une carte ou arrêter, de façon à obtenir la meilleure main possible.
Finalement, le croupier révèle sa carte cachée et tire sur un total de 16 ou moins.
Un joueur gagne sa mise si sa main est meilleure que celle du croupier. Il récupère sa mise si sa main est
égale à celle du croupier. Il perd sa mise si son total est supérieur à 21 ou inférieur au total du croupier.
Le jeu habituel dans les casinos comporte plusieurs autres règles, comme partager les paires, doubler la
mise et assurer sa main. Ces règles ne sont pas considérées dans le présent exemple.
6.7.2
Ports d’entrée et de sortie
On va considérer un joueur de blackjack qui suit la stratégie de base décrite plus haut.
En plus d’un signal d’horloge et de réinitialisation, le joueur de blackjack a un signal d’entrée
valeurCarte qui indique la carte qui lui est donnée, et un signal de contrôle carteValide, indiquant qu’une nouvelle carte est disponible.
Il a trois signaux de sortie : tirer, indiquant qu’il veut une autre carte, depasse, indiquant une main
dont la valeur est supérieure à 21, et total, indiquant la valeur de sa main.
Le code VHDL pour la déclaration d’une entité respectant ces spécifications est donné à l’Exemple 6-12.
INF3500 : Conception et réalisation de systèmes numériques
101
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
architecture arch6 of multiplicateur is
signal multiplicande : unsigned(W - 1 downto 0);
signal facteur : unsigned(W - 1 downto 0);
signal produit : unsigned(2 * W downto 0);
constant compteurmax : positive := W - 1;
signal compteur : natural range 0 to compteurmax;
type type_etat is (attente, addition, decalage);
signal etat : type_etat;
begin
process (CLK, reset)
begin
if rising_edge(CLK) then
if reset = '1' then
etat <= attente;
else
case etat is
when attente =>
if chargeA = '1' then
multiplicande <= entree;
end if;
if chargeB = '1' then
facteur <= entree;
end if;
compteur <= compteurmax;
if go = '1' then
etat <= addition;
produit <= (others => '0');
else
etat <= attente;
end if;
when addition =>
if (facteur(0) = '1') then
produit(2 * W downto W) <=
produit(2 * W downto W) + multiplicande;
end if;
etat <= decalage;
when decalage =>
facteur <= shift_right(facteur, 1);
produit <= shift_right(produit, 1);
if (compteur = 0) then
etat <= attente;
else
etat <= addition;
compteur <= compteur - 1;
end if;
when others =>
etat <= attente;
end case;
end if;
end if;
end process;
-- signal de sortie
F <= produit(2 * W - 1 downto 0);
fini <= '1' when (etat = attente) else '0';
end arch6;
Exemple 6-11 – description ‘RTL-implicite’ du multiplicateur série
INF3500 : Conception et réalisation de systèmes numériques
102
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
library IEEE;
use IEEE.std_logic_1164.all;
entity blackjack is
port (
clk: in std_logic;
reset: in std_logic;
carteValide : in std_logic;
valeurCarte: in integer range 2 to 11;
tirer: out std_logic;
depasse: out std_logic;
total: out integer range 0 to 31
);
end blackjack;
Exemple 6-12 – interface du joueur de blackjack avec le monde extérieur
6.7.3
Chemin des données
Le chemin des données pour le joueur de blackjack est très simple. Il comporte un accumulateur pour
compter le total de la main du joueur. Il est montré à la Figure 6-15. Il comporte aussi un mécanisme pour
soustraire la valeur 10 de la somme, dans le cas où un débordement s’effectue mais que la main est ‘facile’. Le code VHDL correspondant est donné à l’Exemple 6-13.
valeurCarte
moinsDix
-10
0
1
additioneur
calculeSomme
initSomme
clk
load
reset
somme
Figure 6-15 – chemin des données pour joueur de blackjack – diagramme
cheminDonnees : process (clk)
begin
if rising_edge(clk) then
-- registre de la somme
if initSomme = '1' then
somme <= 0;
elsif calculeSomme = '1' then
if moinsDix = '1' then
somme <= somme - 10;
else
somme <= somme + valeurCarte;
end if;
end if;
end if;
end process;
Exemple 6-13 – chemin des données pour joueur de blackjack – code VHDL
INF3500 : Conception et réalisation de systèmes numériques
103
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
6.7.4
Unité de contrôle : machine à états
On peut représenter le comportement du joueur de blackjack à l’aide du diagramme d’états montré à la
Figure 6-16. La machine comporte six états. Dans l’état de départ, la machine et le chemin des données
sont réinitialisés. Dans l’état tire, le système attend une nouvelle carte. Quand le signal d’entrée
carteValide est activé, la machine passe à l’état ajoute. Dans l’état ajoute, la nouvelle somme
est calculée, et le nombre d’as faciles est incrémenté si la carte est un as. À partir de l’état vérifie, il y
a trois transitions possibles, qui sont indiquées dans l’ordre sur le diagramme. Si la somme est supérieure
à 21 mais que la main est facile, on passe à l’état corrige. Si la somme est supérieure à 16, on a terminé.
Si la somme est inférieure à 17, on retourne à l’état tire pour obtenir une nouvelle carte. Dans l’état
corrige, la somme est ajustée pour tenir compte du fait qu’on considère un as ayant la valeur 1, et on
réduit le nombre d’as faciles présents dans la main.
reset
carteValide = ‘1’
depart
ajoute
tire
somme <= 0
somme <= somme + valeurCarte
tirer <= ‘1’
valeurCarte = 11 : n_asfacile++
n_asfacile <= 0
3: sinon
corrige
fini
vérifie
somme <= somme – 10
n_asfacile--
1: somme > 21 ET
n_asfacile > 0
2: somme > 16
Figure 6-16 – machine à états pour le joueur de blackjack
6.7.5
Unité de contrôle : signaux et code VHDL
L’unité de contrôle doit implémenter la machine à états montrée à la Figure 6-16. Elle doit surtout générer
les signaux de contrôle identifiés à la Figure 6-15 en fonction de l’état de la machine et des entrées. Le
Tableau 6-2 résume les signaux de contrôle et les conditions nécessaires pour que chacun soit activé.
Le signal carteValide est un port d’entrée du processeur, contrôlé par le dispositif qui distribue les
cartes au processeur de blackjack.
L’Exemple 6-14 donne le code VHDL pour l’unité de contrôle du processeur. La description de l’unité de
contrôle comporte deux parties : un processus pour la machine à états et un groupe d’énoncés concurrents
pour les signaux de sortie et de contrôle. Les signaux de contrôle et le signal qui contient l’état doivent
être déclarés dans la partie déclarative de l’architecture afin d’être visibles dans toute celle-ci. Il faut se
méfier en décrivant le processeur en VHDL afin de ne pas créer des bascules sans les désirer, ce qui affecterait la synchronisation de la machine.
signal de contrôle
du chemin des données
condition pour activation
calculeSomme
tire OU corrige
initSomme
depart
moinsDix
corrige
Tableau 6-2 – détails de l’unité de contrôle – blackjack
INF3500 : Conception et réalisation de systèmes numériques
104
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
-- machine a etats de l'unité de contrôle
controle : process (CLK, reset)
variable n_asfacile : natural := 0;
begin
if rising_edge(CLK) then
if reset = '1' then
etat <= depart;
else
case etat is
when depart =>
n_asfacile := 0;
etat <= tire;
when tire =>
if (carteValide = '1') then
etat <= ajoute;
end if;
when ajoute =>
if valeurCarte = 11 then
n_asfacile := n_asfacile + 1;
end if;
etat <= verifie;
when verifie =>
if somme > 21 then
if (n_asfacile > 0) then
etat <= corrige;
else
etat <= fini;
end if;
elsif somme > 16 then
etat <= fini;
else
etat <= tire;
end if;
when corrige =>
etat <= verifie;
n_asfacile := n_asfacile - 1;
when fini =>
etat <= fini;
when others =>
etat <= depart;
end case;
end if;
end if;
end process;
-- signaux de sortie
total <= somme;
tirer <= '1' when etat = tire else '0';
depasse <= '1' when etat = fini and somme > 21 else '0';
-- signaux de controle
initSomme <= '1' when etat = depart else '0';
moinsDix <= '1' when etat = corrige else '0';
calculesomme <= '1' when etat = tire or etat = corrige else '0';
Exemple 6-14 – unité de contrôle pour joueur de blackjack – code VHDL
INF3500 : Conception et réalisation de systèmes numériques
105
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
6.8
Exercices
1. Donner un modèle VHDL général pour une machine de Moore et un modèle VHDL général pour une
machine de Mealy, chacun utilisant deux processus.
2. Un circuit séquentiel a deux bascules dont les sorties sont A et B, deux entrées X et Y, et une sortie Z.
Donnez le diagramme d’états du circuit pour les équations d’états et de sortie suivantes :
A  XY  XA
B   XB  XA
Z  XB
3. Comparez en vos propres mots les styles de description d’un circuit séquentiel décrits aux sections
6.3.1 et 6.3.2.
4. Lequel des styles décrits à la section 6.3.4 préférez-vous? Pourquoi? Quels sont les critères de comparaison?
5. Un circuit séquentiel a une entrée de un bit et une sortie de un bit. La sortie doit être active quand la
séquence d’entrée « 101 » est détectée. Donner un diagramme d’états et un modèle VHDL pour ce
circuit. Vérifiez son fonctionnement par simulation.
6. Un circuit séquentiel a une entrée de un bit et une sortie de un bit. La sortie doit être active quand la
séquence d’entrée correspond au code ASCII de votre initiale est détectée. Donner un diagramme
d’états et un modèle VHDL pour ce circuit. Vérifiez son fonctionnement par simulation.
7. Un circuit séquentiel a une entrée de un bit et une sortie de un bit. La sortie doit être active quand la
séquence d’entrée « 0010 » ou bien la séquence d’entrée « 1100 » est détectée. Donner un diagramme
d’états et un modèle VHDL pour ce circuit. Vérifiez son fonctionnement par simulation.
8. Donnez la description en VHDL d’un cadenas numérique à cinq chiffres entre 0 et 9. Le cadenas est
doté d’un bouton entrer qui fait office d’horloge, et de quatre bits permettant de spécifier le
chiffre. Une sortie indique si le cadenas doit être verrouillé ou non. Votre code doit être suffisamment
général pour qu’on puisse facilement changer la combinaison en modifiant une seule ligne du code.
Donner un diagramme d’états et un modèle VHDL pour ce circuit. Vérifiez son fonctionnement par
simulation.
9. Donnez la description en VHDL d’un circuit numérique pour contrôler les feux de circulation d’une
intersection entre une route principale et une route secondaire. Le feu doit demeurer vert sur la route
principale, sauf quand un senseur sous la chaussée de la route secondaire détecte la présence d’une
voiture. Le feu doit alors passer au vert pour la route secondaire pendant une période de 30 secondes,
après quoi il revient au vert pour la route principale. Supposez que vous avez accès à une horloge de 1
Hz. Donner un diagramme d’états et un modèle VHDL pour ce circuit. Vérifiez son fonctionnement
par simulation.
10. Donnez un circuit combinatoire itératif pour effectuer l’addition de deux nombres de n bits. Comme
module de base, utilisez l’additionneur à 3 bits de l’Exemple 2-1. Modifiez ensuite votre circuit pour
utiliser un seul module avec une seule bascule D. Vérifiez son fonctionnement par simulation.
11. Modifiez le code VHDL de l’Exemple 6-2 pour offrir une visibilité aux variables d’état au monde
extérieur.
12. Modifiez le code VHDL de l’Exemple 6-5 pour offrir une visibilité aux variables d’état au monde
extérieur.
13. Faites la conception d’un processeur pour un ascenseur à deux étages. Les entrées du système sont
l’étage courant de l’ascenseur, les boutons de contrôle à l’intérieur de l’ascenseur et les boutons
INF3500 : Conception et réalisation de systèmes numériques
106
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
d’appels aux différents étages. Les sorties du système sont les commandes au moteur de l’ascenseur
et les indicateurs lumineux dans l’ascenseur et aux étages. Ce processeur ne devrait pas comporter de
chemin de données.
a. Donnez un diagramme de vue d’ensemble du système, avec la liste des ports d’entrée et de sortie.
b. Donnez un diagramme d’états du système.
14. Faites la conception d’un processeur pour une machine distributrice. Supposez que vous avez un module qui accepte des pièces et qui donne, sur 8 bits, la valeur en sous de la dernière pièce reçue. Une
constante doit permettre de fixer le prix de l’item à distribuer. L’item doit être distribué quand le total
des pièces reçues est égal ou supérieur au prix de l’item. Supposez une version simple où la monnaie
n’est pas rendue.
a. Donnez un diagramme de vue d’ensemble du système, avec la liste des ports d’entrée et de sortie.
b. Donnez un diagramme d’états du système.
c. Donnez un diagramme du chemin des données.
15. Faites la conception d’un processeur pour un chronomètre d’une résolution de 0.1 s avec un bouton
pour démarrer et arrêter et un bouton permettant de saisir un temps intermédiaire. Supposez que vous
avez accès à une horloge de 10 Hz.
16. Faites la conception d’un processeur qui reçoit la lecture de température d’un moteur à chaque coup
d’horloge. Le processeur doit calculer la moyenne des températures des 5 derniers échantillons et activer un ventilateur si la température moyenne est supérieure à un seuil S2 spécifié par l’utilisateur. Le
ventilateur doit être désactivé quand la température baisse sous un niveau S1 aussi spécifié par
l’utilisateur. Si la température dépasse un troisième seuil S3, une alarme doit être activée. On suppose
que S1 < S2 < S3.
17. Faites la conception d’un processeur pour un télémètre laser. Le télémètre a un bouton pour déclencher la prise de mesure. Quand le bouton est pressé, une impulsion lumineuse est générée et un chronomètre est activé. Quand l’écho de l’impulsion est perçu par un détecteur, le chronomètre est arrêté
et la distance est mesurée en divisant le temps par la vitesse de propagation de la lumière dans l’air.
Discutez de la précision de votre appareil en fonction des différents paramètres de design.
INF3500 : Conception et réalisation de systèmes numériques
107
v. 2.5, juillet 2013
Chapitre 6 : Conception d’unités de contrôle
INF3500 : Conception et réalisation de systèmes numériques
108
v. 2.5, juillet 2013
Chapitre 7
7.1
Vérification de circuits numériques
Concepts fondamentaux
La vérification est un processus par lequel on vérifie qu’un design rencontre bien ses spécifications. Sauf
pour les circuits les plus simples, la vérification complète d’un circuit est un problème très difficile. Dans
l’industrie de la conception numérique, on considère en général que le processus de vérification nécessite
autant d’efforts que le processus de conception lui-même.
La vérification d’un circuit est un art qui repose sur la maîtrise des trois principes suivants :

la compréhension de la spécification;

le contrôle des entrées et de signaux internes du circuit à vérifier; et,

l’observation des sorties, des signaux internes et de l’état du circuit à vérifier.
Un banc d’essai est un module ou un programme qui permet d’appliquer des vecteurs de test ou stimuli à
un circuit et d’observer sa sortie dans le but de vérifier que le circuit rencontre ses spécifications. Un banc
d’essai doit donc être décrit en fonction des spécifications du système. La Figure 7-1 illustre la structure
d’un banc d’essai.
banc d’essai
réponses attendues
observation
des réponses
génération de
vecteurs de
test et de
réponses
attendues
fichier de
stimuli et
réponses
succès/échec
comparaison
aux réponses
attendues
vecteurs de test
circuit à vérifier
réponses
fichier des
résultats
Figure 7-1 – banc d’essai
Un banc d’essai doit effectuer les tâches suivantes :

instancier le circuit à vérifier;

générer des vecteurs de test et les appliquer aux ports d’entrée du circuit;

[optionnel mais utile]: générer automatiquement des réponses attendues aux vecteurs de test;

[optionnel mais utile]: comparer les réponses du circuit aux réponses attendues, et indiquer toute différence entre les deux par une condition d’erreur; et,

[optionnel mais utile]: lire des vecteurs de test et des réponses attendues d’un fichier, et enregistrer les
réponses du circuit ainsi que les résultats de la vérification dans un autre fichier.
On peut décrire un banc d’essai dans tout langage de programmation. Cependant, il y a des avantages
importants à le décrire dans le même langage que le circuit à vérifier. Le langage VHDL est d’une richesse amplement suffisante pour permettre d’écrire des bancs d’essai sophistiqués sans avoir à recourir à
un autre langage. Quand on décrit un banc d’essai en VHDL, on n’est pas restreint par les mêmes contraintes que lors de la description d’un circuit devant être synthétisé avec des composantes logiques. On
INF3500 : Conception et réalisation de systèmes numériques
109
v. 2.42, décembre 2009
Chapitre 7 : Vérification de circuits numériques
peut utiliser toutes les caractéristiques du langage, ce qui s’apparente à travailler avec n’importe quel
langage de haut niveau comme C ou Java.
Avec VHDL, l’utilisation de banc d’essai consiste en général à définir une entité à l’intérieur de laquelle
des stimuli sont générés et appliqués aux entrées d’une instance du circuit à vérifier. Un simulateur est
utilisé pour instancier et exécuter le banc d’essai.
7.2
Banc d’essai de base et clause after
Considérons le circuit de l’additionneur à 3 bits de l’Exemple 2-1. Le rôle de ce circuit est de calculer la
somme des trois bits en entrée Cin, X et Y, et de représenter la somme sur les deux bits Cout et S.
L’Exemple 7-1 illustre un banc d’essai pouvant servir à stimuler ce circuit pour en vérifier le fonctionnement.
library ieee;
use ieee.std_logic_1164.all;
entity add3bitsTB is
end add3bitsTB;
architecture arch1 of add3bitsTB is
component add3bits -- déclaration du module à vérifier
port (Cin, X, Y : in std_logic; Cout, S : out std_logic);
end component;
-- signaux
signal Cin
signal X :
signal Y :
pour les vecteurs de tests
: std_logic;
std_logic;
std_logic;
-- signaux pour les réponses
signal Cout : std_logic;
signal S : std_logic;
begin
-- instanciation du module à vérifier
UUT : add3bits port map (Cin, X, Y, Cout, S);
-- on applique des vecteurs de test
Cin <= '0' after 0 ns, '1' after 40 ns;
Y <= '0' after 0 ns, '1' after 20 ns, '0' after 40 ns, '1' after 60 ns;
X <= '0' after 0 ns, '1' after 10 ns, '0' after 20 ns, '1' after 30 ns,
'0' after 40 ns, '1' after 50 ns, '0' after 60 ns, '1' after 70 ns;
end arch1;
Exemple 7-1 – banc d’essai de base utilisant la clause after
On remarque que l’entité définissant le banc d’essai, add3bitsTB, n’a ni port d’entrée ni port de sortie.
Ceci est conforme au diagramme de la Figure 7-1. Dans la partie déclarative de l’architecture, on déclare
le module à vérifier qui est add3bits. On déclare ensuite des signaux internes au banc d’essai pour
stimuler le module et observer ses réponses. Ces signaux ont ici les mêmes identificateurs que les ports du
module à vérifier, mais ce n’est pas nécessaire. Dans le corps de l’architecture, on déclare le module à
vérifier. L’étiquette associée au module peut être n’importe quel identificateur valable, mais on choisit
souvent « UUT » pour Unit Under Test. On applique à ses ports les signaux des vecteurs de test et de
réponses.
INF3500 : Conception et réalisation de systèmes numériques
110
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
Dans l’exemple, la génération des vecteurs de test est faite à l’aide de la clause after associée à des
assignations concurrentes. La clause after permet de spécifier le moment auquel les signaux doivent
prendre différentes valeurs. Elle comporte une expression de temps, composée d’une quantité et d’une
unité. L’unité « ns » signifie « nanoseconde. » La simulation est réputée débuter au temps T = 0 s.
L’observation des réponses du circuit est faite uniquement par le simulateur et pas par le banc d’essai.
Simulation d’un modèle VHDL
7.3
La simulation du code HDL permet au concepteur de vérifier que la description est conforme aux spécifications. Cette étape est très importante et requiert une grande proportion de l’effort de design. Un compilateur lit le code HDL et vérifie que la syntaxe du langage est respectée. Il génère une description
intermédiaire du code qui peut ensuite être exécutée par un simulateur.
7.3.1
Simulation d’événements concurrents
Un simulateur de modèle VHDL doit simuler l’opération d’événements concurrents et leur assigner des
« moments » où ils se produisent. Pour effectuer cette tâche, le fonctionnement du simulateur repose sur
trois concepts fondamentaux :

une liste d’événements;

une liste des dépendances des signaux; et,

le concept des délais delta.
Le simulateur maintient en tout temps une liste d’événements à simuler. Un événement est un changement
de valeur à apporter à un signal, comme le faire passer de ‘1’ à ‘0’. La liste des dépendances des signaux
indique au simulateur, pour chaque signal, la liste des signaux dont il dépend. Lorsqu’un événement se
produit sur un signal, le simulateur ajoute l’évaluation des signaux qui dépendent de ce signal à la liste
des événements à simuler. Lors de l’évaluation de la valeur de ces autres signaux, de nouveaux événements peuvent être générés. Ce processus se poursuit tant que la liste des événements n’est pas vide.
On a vu que certaines assignations de signaux peuvent avoir lieu à des temps précis, par exemple en utilisant la clause after. Il est possible que plus d’un signal change de valeur à un moment donné. Le simulateur peut traiter plusieurs événements simultanément grâce aux délais delta. Un délai delta, dont le
symbole est ‘’, est un temps infinitésimalement court nécessaire à l’évaluation d’un événement sur la
liste d’événements. Il est possible que plusieurs événements soient simulés tour à tour en plusieurs délais
delta consécutifs avant que la valeur de tous les signaux ne se stabilise. Cependant, du point de vue du
temps de simulation, la somme de tous ces délais delta reste nulle. Le délai delta est un mécanisme abstrait pour permettre la simulation d’événements concurrents par un procédé séquentiel.
Il est possible, lors de la simulation d’un modèle, que la valeur de certains de ses signaux ne se stabilise
pas. Le temps de simulation ne peut donc pas avancer, et seul le nombre de deltas change. Un simulateur
doit pouvoir détecter cet état de chose, s’arrêter lui-même et afficher un message d’erreur.
La simulation débute au temps 0. Tous les processus, les assignations concurrentes et les instanciations de
composantes sont placés sur la liste des événements. L’un deux est choisi et est exécuté. Toutes les assignations de valeur à des signaux à l’intérieur du processus sont placées sur la liste des événements à traiter au temps 0 + , ou à un moment spécifié dans l’assignation du signal, comme par exemple avec une
clause after. Tous les autres processus sont exécutés à leur tour, et des événements sont aussi ajoutés à
la liste des événements au temps 0 +  ou plus tard. Quand tous les processus ont été exécutés, le temps
de simulation est avancé au temps 0 + , et le processus recommence. Tous les changements de valeur de
signaux prévus pour ce moment ont lieu. Si ces signaux sont sur la liste de sensitivité de processus,
l’exécution de ces processus est ajoutée à la liste des événements au temps 0 + 2. Le cycle se répète tant
que la liste des événements contient encore des événements à traiter à un temps 0 + n. Ensuite, le temps
INF3500 : Conception et réalisation de systèmes numériques
111
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
de simulation est avancé selon le moment du prochain événement dans la liste des événements. Le cycle
se répète tant que la liste des événements n’est pas vide.
7.3.2
Assignations à des objets des catégories signal et variable dans un processus
Dans un processus, les énoncés sont exécutés de façon séquentielle. Les objets des catégories variable
et signal sont traitées différemment. Cette section résume ces différences.
Dans une assignation, on retrouve une cible et une expression.
Quand la cible est une variable, celle-ci prend immédiatement la valeur qui lui est assignée. Quand la
cible est un signal, l’assignation est placée sur la liste des événements. Si l’assignation ne contient pas de
clause de délai explicite, la clause implicite « after 0 ns » est ajoutée, ce qui signifie que
l’assignation aura lieu un délai delta plus tard. En pratique, cela signifie que l’assignation n’aura pas lieu
tant que l’exécution du processus ne sera pas suspendue par un énoncé wait. Les processus avec une
liste de sensitivité contiennent un énoncé wait implicite après tous les énoncés explicites du processus.
Lors de l’évaluation d’une expression, les valeurs des variables correspondent à leur valeur instantanée au
moment de l’évaluation. Pour les signaux, leur valeur est celle en vigueur au début de l’exécution du processus. Toute assignation de valeur à un signal pendant l’exécution du processus est ajoutée à la liste des
événements, mais ne se produit pas tant qu’un énoncé wait explicite ou implicite n’est pas exécuté.
Si un processus contient plus d’une assignation de valeur à un signal, et que ces assignations contiennent
des clauses de délais explicites ou implicites identiques, c’est la dernière assignation dans la suite des
énoncés séquentiels qui a précédence.
Quand le processus est lancé la première fois, les variables du processus sont initialisées. Les variables
conservent leurs valeurs entre différentes exécutions du processus. Pour les assignations à des variables,
l'ordre est donc critique pour interpréter le sens du comportement qui est décrit.
Pour les signaux, l'ordre est critique aussi. Cependant, si tous les signaux qui font l'objet d'une assignation
sont placés dans la liste de sensitivité du processus, alors l'ordre n'est plus important. En effet, le processus sera relancé chaque fois qu'un des signaux dans sa liste de sensitivité subit une assignation. Les assignations des signaux sont prévues pendant l'exécution du processus, mais ne sont effectuées qu'à la fin de
l'exécution de celui-ci.
De plus, l’utilisation de signaux à l’intérieur d’un processus peut parfois résulter en un comportement
différent entre la synthèse et la simulation. Une façon d’éviter cet état de chose est d’ajouter à la liste de
sensitivité tous les signaux qui font l’objet d’une assignation à l’intérieur du processus.
7.4
Vecteurs de test encodés dans un tableau de constantes
L’utilisation de la clause after dans l’Exemple 7-1 fonctionne mais est lourde quand il y a beaucoup de
vecteurs de test à générer et à appliquer. De plus, il est difficile de maintenir la liste des vecteurs de test et
de la modifier quand elle est exprimée de cette manière. Une façon plus efficace consiste à coder la liste
des vecteurs dans un tableau de constantes, et d’appliquer chaque élément du vecteur au module à vérifier, tour à tour. Cette approche est illustrée dans l’Exemple 7-2.
Dans cet exemple, on définit un nouveau type, tableauSLV3, comme un tableau d’éléments de type
std_logic_vector de trois bits chacun. On définit ensuite une constante, vecteurs, de ce nouveau
type. Cette constante est un tableau prédéfini de huit éléments avec les valeurs que l’on veut appliquer au
module à vérifier. On remarque que le type tableauSLV3 ne fixe pas le nombre d’éléments du tableau.
C’est l’initialisation de la constante vecteurs qui en détermine la taille implicitement.
Dans le corps de l’architecture, le module à vérifier est tout d’abord instancié. Ensuite, un processus est
déclaré. Il comporte une boucle qui itère à travers les éléments du tableau de vecteurs de test et les ap-
INF3500 : Conception et réalisation de systèmes numériques
112
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
plique successivement au module à vérifier. Les bornes de la boucle sont déterminées statiquement lors de
la compilation grâce aux attributs low et high du tableau, qui représentent respectivement l’index du
premier et du dernier élément du tableau et qui valent ici 0 et 7 respectivement. Pour avoir à éviter
d’appliquer les vecteurs de test bit par bit, on utilise la cible d’assignation combinée (Cin, Y, X).
architecture arch2 of add3bitsTB is
component add3bits -- déclaration du module à vérifier
port (Cin, X, Y : in std_logic; Cout, S : out std_logic);
end component;
-- signaux pour les vecteurs de tests
signal Cin, X, Y : std_logic;
-- signaux pour les réponses
signal Cout, S : std_logic;
type tableauSLV3 is array (natural range <>) of std_logic_vector(2 downto 0);
constant vecteurs : tableauSLV3 :=
("000", "001", "010", "011", "100", "101", "110", "111");
begin
-- instanciation du module à vérifier
UUT : add3bits port map (Cin, X, Y, Cout, S);
process -- application des vecteurs de test emmagasinés dans le tableau
begin
for k in vecteurs'low to vecteurs'high loop
(Cin, Y, X) <= vecteurs(k);
wait for 10 ns;
end loop;
end process;
end arch2;
Exemple 7-2 – banc d’essai utilisant des vecteurs de test codés dans un tableau de constantes
L’énoncé wait for 10 ns a pour effet de suspendre l’exécution du processus pendant 10 ns à chaque
itération de la boucle. Cette pause nécessaire a pour effet de laisser se stabiliser les sorties du module à
vérifier. La durée de 10 ns est arbitraire, mais un énoncé wait est essentiel pour que l’on puisse observer
des sorties différentes correspondant aux différents vecteurs d’entrée. Sans cet énoncé, tous les vecteurs
de test seraient appliqués à l’entrée du module à vérifier au même instant de simulation, mais avec des
délais delta différents.
La durée de la simulation n’est pas déterminée dans ce banc d’essai, c’est plutôt lors du lancement du
simulateur qu’on doit la déterminer. Comme il y a 8 vecteurs de test, appliqués à intervalles de 10 ns, un
temps de simulation de 80 ns est requis. Si la durée est supérieure à 80 ns, le processus est relancé et la
boucle recommence avec le premier élément du tableau.
7.5
Génération algorithmique de vecteurs de test
7.5.1
Vérification exhaustive
L’utilisation d’un tableau montrée à l’Exemple 7-2 convient bien pour des ensembles de vecteurs de test
de taille limitée et quand des cas spéciaux doivent être vérifiés. Pour un circuit combinatoire, il est parfois
possible de faire une vérification exhaustive, c'est-à-dire qu’on applique tous les vecteurs de test possibles
au module à vérifier. Dans un pareil cas, l’utilisation d’un tableau ne convient qu’aux circuits les plus
simples, avec peu d’entrées.
INF3500 : Conception et réalisation de systèmes numériques
113
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
Une approche plus sophistiquée consiste à générer algorithmiquement les vecteurs de test désirés. Par
exemple, pour un test exhaustif, on peut utiliser directement le compteur de boucle et effectuer une conversion de type si nécessaire. Cette approche est montrée dans l’Exemple 7-3.
library ieee;
use ieee.numeric_std.all;
architecture arch3 of add3bitsTB is
component add3bits -- déclaration du module à vérifier
port (Cin, X, Y : in std_logic; Cout, S : out std_logic);
end component;
-- signaux pour les vecteurs de tests
signal Cin, X, Y : std_logic;
-- signaux pour les réponses
signal Cout, S : std_logic;
begin
-- instanciation du module à vérifier
UUT : add3bits port map (Cin, X, Y, Cout, S);
process -- application exhaustive des vecteurs de test
begin
for k in 0 to 7 loop
(Cin, Y, X) <= to_unsigned(k, 3);
wait for 10 ns;
end loop;
end process;
end arch3;
Exemple 7-3 – vérification exhaustive
La fonction to_unsigned est définie dans le package numeric_std. Cette fonction accepte en paramètres un entier positif à convertir et un entier indiquant le nombre de bits à utiliser. Le type de retour
est unsigned, défini dans le package numeric_std, dont la définition est identique à
std_logic_vector. Le reste de l’exemple est identique à l’exemple précédent.
7.5.2
Vérification pseudo-aléatoire
Pour certains circuits, une vérification exhaustive ne peut être considérée à cause du très grand nombre de
vecteurs de tests possible. Par exemple, un circuit à 64 entrées nécessiterait 2 64 vecteurs de test, soit plus
de 18 × 1018 vecteurs. Une possibilité dans un cas semblable est de vérifier quelques cas particuliers en
utilisant un tableau de valeur, puis d’utiliser une longue séquence de nombres pseudo-aléatoires.
L’utilisation de nombres pseudo-aléatoires est démontrée à l’Exemple 7-4, bien que pour un circuit de
cette taille la meilleure approche est la vérification exhaustive montrée à l’Exemple 7-3.
Dans l’Exemple 7-4, on utilise la procédure uniform, définie dans le package math_real. Cette procédure prend trois paramètres en entrée : deux valeurs « graines » pour guider la génération de nombres
pseudo-aléatoires, et le nombre pseudo-aléatoire lui-même. Le nombre obtenu est de type real et est
dans l’intervalle ouvert (0.0, 1.0). Comme on désire un nombre entier entre 0 et 7 inclusivement, des opérations de conversion d’échelle et de conversion de type explicites sont nécessaires dans le processus.
INF3500 : Conception et réalisation de systèmes numériques
114
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
library ieee;
use ieee.numeric_std.all;
use ieee.math_real.all;
architecture arch4 of add3bitstb is
component add3bits -- déclaration du module à vérifier
port (Cin, X, Y : in std_logic; Cout, S : out std_logic);
end component;
-- signaux pour les vecteurs de tests
signal Cin, X, Y : std_logic;
-- signaux pour les réponses
signal Cout, S : std_logic;
begin
-- instanciation du module à vérifier
UUT : add3bits port map (Cin, X, Y, Cout, S);
process -- génération aléatoire de vecteurs de test
variable seed1 : positive := 1;
variable seed2 : positive := 2;
variable aleatoire : real;
variable t : integer := -1;
begin
uniform(seed1, seed2, aleatoire); -- 0.0 < aleatoire < 1.0
aleatoire := floor(aleatoire * 8.0); -- 0.0 <= aleatoire <= 7.0
t := integer(aleatoire); -- 0 <= t <= 7
(Cin, Y, X) <= to_unsigned(t, 3);
wait for 10 ns;
end process;
end arch4;
Exemple 7-4 – vérification par des vecteurs de test pseudo-aléatoires
7.6
Observation et évaluation des réponses : assertions
Dans les exemples des sections précédentes, les réponses du circuit à vérifier n’étaient pas considérées par
les bancs d’essai. On laissait plutôt à l’utilisateur le soin de les observer par l’entremise du simulateur,
possiblement en faisant tracer les signaux correspondants aux sorties du module. Cette approche ne convient que pour les petits circuits avec peu de vecteurs de test à considérer, peu de sorties, et peu de cas
spéciaux.
L’observation et la comparaison automatisées des réponses du module à vérifier est une approche très
puissante qui économise beaucoup de temps pour tous les circuits non triviaux. Pour toute condition où le
circuit ne produit pas les réponses attendues, le banc d’essai devrait générer un message d’avertissement
indiquant le moment où l’erreur s’est produite, la valeur du vecteur de test, la valeur des réponses observées et la valeur des réponses attendues.
La production de messages à l’utilisateur en VHDL peut se faire à l’aide des énoncés assert et
report. Le format de ces énoncés est montré à l’Exemple 7-5. Le message est affiché à la console si
l’expression logique est fausse. L’énoncé report peut être utilisé seul, ce qui correspond à le précéder
de l’énoncé assert false. Il a pour effet d’afficher une chaîne de caractères à la console.
INF3500 : Conception et réalisation de systèmes numériques
115
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
[assert expression_logique]
report message severity [note, warning, error, ou failure];
Exemple 7-5 – énoncés assert et report
Pour démontrer l’observation et l’évaluation automatisée des réponses d’un circuit, considérons le module
VHDL montré dans l’Exemple 7-6. Le module detecteurPremier accepte en entrée un vecteur
d’éléments de type std_logic interprété comme un nombre binaire non signé (type unsigned, défini
dans le package numeric_std). Il a une sortie binaire qui indique si I à l’entrée est un nombre premier
ou non. Pour implémenter cette fonction combinatoire, on utilise une assignation choisie. Les choix acceptables sont séparés par la barre verticale: ‘|’. L’utilisation de la fonction to_integer du package
numeric_std augmente de façon importante la lisibilité du code. Cette fonction polymorphique accepte un paramètre du type unsigned et retourne un integer. Le code de l’Exemple 7-6 comporte
une erreur, puisque le nombre 63 n’est pas premier.
library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;
entity detecteurPremier is
port (
I : in unsigned(5 downto 0);
F : out std_logic
);
end detecteurPremier;
architecture flotdonnees of detecteurPremier is
begin
with to_integer(I) select
F <=
'1' when 2 | 3 | 5 | 7 | 11 | 13 | 17 |
19 | 23 | 29 | 31 | 37 | 41 | 43 |
47 | 53 | 59 | 61 | 63, -- erreur!
'0' when others;
end flotdonnees;
Exemple 7-6 – un module qui indique si un nombre est premier
Un banc d’essai pour vérifier l’opération du module detecteurPremier est proposé dans l’Exemple
7-7. La partie déclarative de l’architecture comporte la déclaration d’une fonction, estPremier. Cette
fonction accepte un paramètre de type integer et retourne une valeur de type boolean. La fonction
détermine si le paramètre est un nombre premier en vérifiant s’il est divisible par les nombres dans
l’intervalle de 2 à sa propre racine carrée. Les cas particuliers sont considérés avant la boucle.
Cette fonction illustre l’utilisation des fonctions sqrt et ceil du package math_real, qui retournent
respectivement la racine carrée et l’entier égal ou supérieur d’un nombre. On observe aussi les conversions explicites de type comme real(n) qui convertit la valeur de n vers le type real. Le langage
VHDL est très fortement typé et exige ces conversions explicites de type lors de l’appel de fonctions.
Dans le corps de l’architecture, on instancie tout d’abord le module à vérifier. Un processus est ensuite
défini pour appliquer de façon exhaustive des vecteurs de test à l’entrée du module. L’énoncé wait est
essentiel car il suspend l’exécution du processus et force ainsi l’assignation immédiate de valeur au signal
I. L’énoncé assert vérifie si la valeur retournée par la fonction estPremier correspond à la valeur
de sortie du module à vérifier. Si ce n’est pas le cas, un message d’erreur est affiché à l’écran.
INF3500 : Conception et réalisation de systèmes numériques
116
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity detecteurPremierTB is
end detecteurPremierTB;
architecture arch1 of detecteurPremierTB is
component detecteurPremier -- déclaration du module à vérifier
port (I : in unsigned(5 downto 0); F : out std_logic);
end component;
signal I : unsigned(5 downto 0); -- signal pour les vecteurs de tests
signal F : std_logic; -- signal pour les réponses
function estPremier(n: integer) return boolean is
variable reponse : boolean := false;
begin
if (n <= 1) then
-- par définition, le premier nombre premier est 2
reponse := false;
elsif (n <= 3) then
reponse := true;
else
reponse := true;
for k in 2 to integer(ceil(sqrt(real(n)))) loop
if (n mod k = 0) then
reponse := false;
exit;
end if;
end loop;
end if;
return reponse;
end estPremier;
begin
-- instanciation du module à vérifier
UUT : detecteurPremier port map (I, F);
process
constant kmax : integer := 63;
begin
for k in 0 to kmax loop -- application exhaustive des vecteurs de test
I <= to_unsigned(k, 6);
wait for 10 ns;
assert (estPremier(k) = (F = '1'))
report "erreur pour l'entrée " & integer'image(k) severity error;
assert k < kmax
report "simulation terminée" severity failure;
end loop;
end process;
end arch1;
Exemple 7-7 – utilisation de assert et report dans un banc d’essai
INF3500 : Conception et réalisation de systèmes numériques
117
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
On remarque que l’énoncé report doit être suivi d’une chaîne de caractères. Comme on veut afficher la
valeur de l’entrée pour laquelle une erreur est détectée, il est nécessaire d’obtenir une chaîne de caractères
à partir de la variable de boucle k qui est implicitement de type integer. Ceci est accompli par
l’expression integer’image(k).
Un deuxième énoncé assert est utilisé pour terminer la simulation quand tous les vecteurs de test ont
été appliqués. Quand la valeur du compteur de boucle atteint le maximum, un message indiquant ce fait
est affiché par l’énoncé report. De plus, en spécifiant une sévérité failure, la plupart des simulateurs
de VHDL interrompent la simulation. Si on n’utilisait pas cet énoncé assert, la simulation du processus
recommencerait dès que la boucle serait terminée parce que le processus n’a pas de liste de sensitivité, et
donc son exécution est toujours placée sur la liste des événements.
La vérification du module estPremier par le banc d’essai proposé dans l’Exemple 7-7 suppose que la
fonction estPremier est elle-même correcte. C’est là un des problèmes difficiles de la vérification
d’un circuit. En général, plus la description du circuit et son modèle algorithmique dans le banc d’essai
sont différentes, plus on a de chances que la vérification permette d’identifier les erreurs. En effet, la probabilité de faire la même erreur dans les deux modèles est d’autant plus faible qu’ils sont très différents.
7.7
Entrées et sorties par fichiers
Lors de la vérification d’un module complexe, on a souvent généré au préalable des groupes de vecteurs
de test et de réponse à partir d’un modèle de très haut niveau. Ce modèle peut avoir été décrit dans un
langage de haut niveau ou avec un environnement comme Matlab. Dans un pareil cas, on fait face à deux
choix : on peut redéfinir le modèle dans un banc d’essai en VHDL, ou bien on peut entreposer les vecteurs et réponses dans un fichier et utiliser un banc d’essai pour les lire.
Le banc d’essai peut aussi écrire ses résultats dans un fichier. Cela est particulièrement utile si la simulation dure plusieurs heures, si on désire obtenir des résultats progressifs, ou si on doit effectuer un traitement plus complexe des résultats dans un autre environnement que le simulateur VHDL. Par exemple, on
pourrait vouloir afficher une image générée sous la forme d’un flux de pixels par un module.
Les entrées et sorties de fichier en VHDL se font à l’aide d’objets de la catégorie file. Comme on traite
du texte lors de ces opérations, on utilise aussi les types et les fonctions définis dans le package textio
qui fait partie du langage.
Considérons à nouveau le module detecteurPremier de l’Exemple 7-6. Au lieu d’écrire une fonction pour déterminer les réponses du circuit, comme dans l’Exemple 7-7, on pourrait avoir utilisé un autre
environnement et avoir une liste de nombres dans un fichier ainsi qu’une indication s’ils sont premiers ou
non. Un tel fichier est montré dans l’Exemple 7-8.
-- colonne1: entiers de 0 à 63
-- colonne2: P pour premier, N pour pas premier
0 N
1 N
2 P
3 P
4 N
5 P
...
Exemple 7-8 – partie d’un fichier contenant des vecteurs de test et des réponses attendues
Un banc d’essai qui utilise ce fichier est proposé à l’Exemple 7-9. La partie déclarative de l’architecture
contient la déclaration d’un objet de catégorie file et de type text, vecteurs. On spécifie le mode
de lecture (read_mode) ainsi que le nom du fichier lors de cette déclaration.
INF3500 : Conception et réalisation de systèmes numériques
118
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
architecture arch2 of detecteurPremierTB is
component detecteurPremier -- déclaration du module à vérifier
port (I : in unsigned(5 downto 0); F : out std_logic);
end component;
signal I : unsigned(5 downto 0); -- signal pour les vecteurs de tests
signal F : std_logic; -- signal pour les réponses
constant filename : string := "premiers.txt";
file vecteurs : text open read_mode is filename;
-- format du fichier:
-- colonne1: entier, colonne2: 'P' pour premier, 'N' pour pas premier
begin
-- instanciation du module à vérifier
UUT : detecteurPremier port map (I, F);
process
variable tampon : line; -- pointeur vers un objet de type string
variable n : integer;
variable c : character;
begin
while not endfile(vecteurs) loop
readline(vecteurs, tampon);
if tampon(1 to 2) /= "--" then -- passer les lignes de commentaires
read(tampon, n); -- lecture de l'entier
read(tampon, c); -- lecture du séparateur
read(tampon, c); -- lecture de l'indication: premier ('P') ou non ('N')
I <= to_unsigned(n, 6);
wait for 10 ns;
assert ((c = 'P') = (F = '1') and (c = 'N') = (F = '0'))
report "erreur pour l'entrée " & integer'image(n) severity error;
end if;
end loop;
deallocate(tampon); -- relâcher la mémoire du tampon
report "simulation terminée" severity failure;
end process;
end arch2;
Exemple 7-9 – banc d’essai lisant un fichier de vecteurs de test et de réponses attendues
Dans un processus, on définit une variable de type line, qui est un pointeur vers un objet de type
string. Le type line est défini dans le package textio. À l’intérieur d’une boucle, on lit successivement chaque ligne du fichier. L’appel de la procédure readline permet de lire une ligne du fichier et
d’y avoir accès par l’entremise de cette variable. Pour chaque ligne, on détermine si c’est une ligne de
commentaire, et dans le cas contraire on lit un entier, le caractère de séparation et l’indication si le
nombre est premier ou non. La procédure read est polymorphique et traite le bon type de données selon
le type de son deuxième paramètre. On applique l’entier au module à vérifier et on force l’assignation par
un énoncé wait. On vérifie ensuite si la sortie du module est conforme aux données du fichier.
INF3500 : Conception et réalisation de systèmes numériques
119
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
Pour terminer, il est nécessaire de libérer la mémoire réservée pour le tampon et de forcer la fin de la simulation, ici par un énoncé report avec une qualification severity failure. Pour la plupart des
simulateurs, il est possible de spécifier quelle action prendre selon les différents niveaux de severity.
Dans la plupart des cas, le niveau failure correspond à un arrêt de la simulation.
L’Exemple 7-10 démontre un banc d’essai qui écrit, dans un fichier et à la console, les vecteurs de test
appliqués au module à vérifier ainsi que ses réponses. Cet exemple est similaire à l’Exemple 7-9, mais
dans ce cas on effectue une vérification exhaustive du module grâce à une boucle. Un objet de catégorie
file et de type text est à nouveau déclaré, mais en mode write_mode.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use ieee.std_logic_textio.all;
architecture arch3 of detecteurPremierTB is
component detecteurPremier -- déclaration du module à vérifier
port (I : in unsigned(5 downto 0); F : out std_logic);
end component;
signal I : unsigned(5 downto 0); -- signal pour les vecteurs de tests
signal F : std_logic; -- signal pour les réponses
constant filename : string := "sortie.txt";
file resultats : text open write_mode is filename;
begin
-- instanciation du module à vérifier
UUT : detecteurPremier port map (I, F);
process
variable tampon : line; -- pointeur vers objet de type string
variable tampon2 : line;
begin
-- La procédure writeline libère le pointeur quand elle a fini,
-- donc il faut construire une copie de l'objet si on veut l'afficher 2 fois.
-- À partir d'un pointeur, on va chercher le contenu avec '.all'.
write(tampon, string'(" ** sortie de simulation, detecteurPremierTB.vhd ** "));
write(tampon2, tampon.all); -- copier la chaîne de caractères
writeline(resultats, tampon); -- écriture dans le fichier
writeline(output, tampon2); -- écriture à la console
for k in 0 to 63 loop -- application exhaustive des vecteurs de test
I <= to_unsigned(k, 6);
wait for 10 ns;
write(tampon, string'("temps: ")); write(tampon, now, unit => ns);
write(tampon, string'(", entier: ") & integer'image(k));
write(tampon, string'(", sortie: ") & std_logic'image(F));
write(tampon2, tampon.all); -- copie la chaîne de caractères
writeline(resultats, tampon); -- écriture dans le fichier
writeline(output, tampon2); -- écriture à la console
end loop;
report "simulation terminée" severity failure;
end process;
end arch3;
Exemple 7-10 – banc d’essai écrivant dans un fichier et à la console
INF3500 : Conception et réalisation de systèmes numériques
120
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
Pour écrire dans un objet de catégorie file, il faut utiliser la procédure writeline. Celle-ci nécessite
une variable de type line en paramètre. Le type line est un pointeur vers un objet de type string. La
procédure write permet d’écrire dans un objet de type string à partir d’un pointeur.
Dans l’Exemple 7-10, la procédure writeline est utilisée deux fois : une fois pour écrire dans le fichier, et une fois pour écrire à la console (objet output de catégorie file défini dans le package
textio). Le problème, c’est que la procédure writeline libère le pointeur à la fin de son exécution.
Pour cette raison, si on désire écrire un message dans un fichier et à la console, il est nécessaire de créer
un deuxième pointeur et d’effectuer une copie de l’objet pointé par ce pointeur. Pour effectuer une copie
de l’objet, on peut avoir accès à son contenu par la notation pointeur.all, où pointeur est le pointeur de l’objet.
Dans l’Exemple 7-10, on note l’utilisation de la fonction now qui retourne le temps présent de simulation.
On remarque aussi l’utilisation de la méthode polymorphique write avec des paramètres de différents
types et avec un nombre variable de paramètres.
7.8
Utilisation de configurations en VHDL
On a vu au Chapitre 2 qu’une entité peut avoir plus d’une architecture, représentant différentes façons de
décrire le comportement de l’entité. Lors de la simulation avec un banc d’essai d’une entité à laquelle sont
associées plus d’une architecture, il est essentiel de spécifier quelle architecture doit être utilisée par la
spécification d’une configuration. Il y a deux façons d’effectuer ce choix.
Premièrement, on peut spécifier l’architecture à utiliser à l’intérieur de la partie déclarative de
l’architecture du banc d’essai. La syntaxe est démontrée dans l’Exemple 7-11. L’étiquette est celle utilisée
pour l’instanciation de la composante.
for étiquette : composante : use entity librairie.entité(architecture);
Exemple 7-11 – spécifier une configuration – méthode #1
Le problème avec cette approche est que l’on doit recompiler l’architecture au complet si on désire changer l’entité et l’architecture associées à l’instanciation d’une composante. Ceci peut être un problème lors
de la description de gros modules ou de modules qui dépendent de plusieurs autres. La deuxième façon de
spécifier l’architecture à utiliser consiste à déclarer une configuration séparément. Cette déclaration est
indépendante de la déclaration de toute entité ou architecture. Elle peut être placée dans un fichier différent. La syntaxe de cette approche est démontrée dans l’Exemple 7-12.
configuration identificateur_de_configuration of entité_à_configurer is
for nom_de_l’architecture_de_l’entité_à_configurer
for étiquette : composante use entity librairie.entité(architecture);
end for;
end for;
end identificateur_de_configuration;
Exemple 7-12 – spécifier une configuration – méthode #2
7.9
Instanciation directe d’une entité
En VHDL, il y a en général plusieurs façons d’accomplir la même chose. Au lieu de déclarer une composante dans la partie de déclarative de l’architecture puis de l’instancier dans son corps, il est possible de
l’instancier directement grâce à une instanciation d’entité. Cette approche est montrée à l’Exemple 7-13.
INF3500 : Conception et réalisation de systèmes numériques
121
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
architecture arch1a of add3bitsTB is
-- signaux
signal Cin
signal X :
signal Y :
pour les vecteurs de tests
: std_logic;
std_logic;
std_logic;
-- signaux pour les réponses
signal Cout : std_logic;
signal S : std_logic;
begin
UUT : entity add3bits(flotdonnees) port map (Cin, X, Y, Cout, S);
-- on applique des vecteurs de test
Cin <= '0' after 0 ns, '1' after 40 ns;
Y <= '0' after 0 ns, '1' after 20 ns, '0' after 40 ns, '1' after 60 ns;
X <= '0' after 0 ns, '1' after 10 ns, '0' after 20 ns, '1' after 30 ns,
'0' after 40 ns, '1' after 50 ns, '0' after 60 ns, '1' after 70 ns;
end arch1a;
Exemple 7-13 – instanciation d’entité, modification de l’Exemple 7-1
L’Exemple 7-13 reprend le code de l’Exemple 7-1. On note que le nom de l’architecture à utiliser est
placé entre parenthèses après le nom de l’entité. Si aucune architecture n’est spécifiée, le simulateur choisit en général la dernière architecture à avoir été compilée pour cette entité.
L’avantage principal de cette approche est que le code est plus compact. Le désavantage est qu’on ne peut
pas utiliser de configurations, donc si on désire changer d’architecture à simuler il faut recompiler le banc
d’essai au complet. Cette approche peut aussi paraître confuse, puisque le mot clé entity est utilisé
dans un deuxième contexte complètement différent du premier.
7.10
Vérification d’un circuit séquentiel synchrone par banc d’essai
7.10.1 Composition d’un banc d’essai pour un circuit séquentiel
Un banc d’essai pour un circuit séquentiel est très similaire à celui pour un circuit combinatoire. La différence principale est qu’il doit mener un signal d’horloge et un signal de réinitialisation. Il devrait effectuer
les tâches suivantes :

déclarer le circuit à vérifier

instancier le circuit à vérifier;

générer un signal d’horloge et un signal de réinitialisation;

générer des vecteurs de test et les appliquer aux ports d’entrée du circuit;

[optionnel mais utile]: générer automatiquement des réponses attendues aux vecteurs de test;

[optionnel mais utile]: comparer les réponses du circuit aux réponses attendues, et indiquer toute différence entre les deux par une condition d’erreur; et,

[optionnel mais utile]: lire des vecteurs de test et des réponses attendues d’un fichier, et enregistrer les
réponses du circuit ainsi que les résultats de la vérification dans un autre fichier.
L’Exemple 7-14 illustre un banc d’essai pour le module décrit à l’Exemple 6-1.
INF3500 : Conception et réalisation de systèmes numériques
122
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
use ieee.std_logic_textio.all;
entity cctsequentielex1TB is
end cctsequentielex1TB;
architecture arch1a of cctsequentielex1TB is
signal reset : std_logic := '0';
signal clk : std_logic := '0';
signal X : std_logic := 'X';
signal Z : std_logic := 'X';
constant periode : time := 10 ns;
begin
clk <= not clk after periode / 2;
reset <=
'0' after 0 ns,
'1' after periode / 4;
-- instanciation du module à vérifier
UUT : entity cctsequentielex1(arch2) port map (reset, clk, X, Z);
process (clk)
constant vecteurX : std_logic_vector := "00001010010011000111";
variable compte : natural range 0 to vecteurX'length := 0;
variable tampon : line; -- pointeur vers objet de type string
begin
if (falling_edge(clk)) then -- *** front différent de l'UUT ***
write(tampon, "temps: "); write(tampon, now, unit => ns);
write(tampon, ", x: " & std_logic'image(x));
write(tampon, ", z: " & std_logic'image(z));
write(tampon, ", compte: " & integer'image(compte));
writeline(output, tampon); -- écriture à la console
if compte = vecteurX'length then
report "simulation terminée" severity failure;
else
X <= vecteurX(compte);
compte := compte + 1;
end if;
end if;
end process;
end arch1a;
Exemple 7-14 – banc d’essai pour le circuit séquentiel de l’Exemple 6-2
7.10.2 Déclaration du circuit à vérifier et sélection d’une architecture
L’instanciation du circuit à vérifier est faite de façon directe comme à l’Exemple 7-13.
7.10.3 Génération d’un signal d’horloge et de réinitialisation
La génération d’un signal d’horloge périodique et d’un signal de réinitialisation peut être faite de façon
très efficace par deux énoncés concurrents dans l’architecture du banc d’essai. Ceci est démontré à
l’Exemple 7-15. On note que l’horloge se voit assigner une valeur initiale dans sa déclaration, puis que
dans l’architecture elle bascule entre deux états à chaque demi-période.
INF3500 : Conception et réalisation de systèmes numériques
123
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
-- dans la partie déclarative de l’architecture
signal clk : std_logic := '0';
constant periode : time := 10 ns;
...
-- dans l’architecture
clk <= not clk after periode / 2;
reset <=
'0' after 0 ns,
'1' after periode / 4;
Exemple 7-15 – signaux d’horloge et de réinitialisation
7.10.4 Génération de vecteurs de test et application au circuit à vérifier
Dans l’Exemple 7-14, on utilise des vecteurs de test encodés dans un tableau de valeur, tel que décrit à la
section 7.4. Les autres approches décrites dans les sections suivantes seraient tout à fait valides aussi, sauf
que la vérification exhaustive est beaucoup plus complexe à effectuer et n’est en général pas possible.
Pour la vérification d’un circuit séquentiel, la synchronisation des vecteurs d’entrée par rapport au signal
d’horloge est très importante. Dans l’Exemple 7-14, on observe que le processus est synchronisé sur un
front descendant d’horloge, alors que le circuit à vérifier est synchronisé sur un front montant. En agissant
ainsi, on s’assure que les entrées ne changent jamais simultanément avec le front d’horloge sur lequel le
circuit à vérifier est actif. Ceci simplifie la tâche de vérification manuelle des chronogrammes produits
par le simulateur.
7.10.5 Observation de l’état interne du module à vérifier pour débogage
Avec VDHL-2002, il n’est pas possible pour un banc d’essai d’observer les signaux internes du circuit
qui est vérifié. Cela signifie donc qu’il est impossible en principe pour le banc d’essai d’observer et de
comparer l’état interne d’un module. Pourtant, l’observation directe de l’état d’une machine à états est
une technique très puissante de débogage. L’observation unique des entrées et sorties permet mal de
suivre l’évolution de la machine dans le temps. Il existe deux solutions à ce problème.
La première solution consiste à utiliser un simulateur qui donne la visibilité à l’intérieur des entités instanciées par le banc d’essai. Il est alors aisé d’observer l’état de la machine ainsi que tout autre signal
interne de celle-ci. Ces signaux peuvent être ajoutés à un chronogramme. Le problème avec cette solution
est qu’elle ne permet pas facilement de vérifier automatiquement, à l’intérieur du banc d’essai, la valeur
de l’état du système par rapport à des valeurs attendues.
La deuxième solution consiste à ajouter un port de sortie à la machine à états qui indiquent l’état de celleci. Le banc d’essai doit lire ces ports comme toute autre sortie de la machine et peut ainsi déterminer si la
machine fonctionne correctement. Le type du port de sortie peut être abstrait, comme une énumération
discutée à la section 6.3.3. Cependant, le type du port doit alors être défini dans un package afin de pouvoir s’en servir dans le banc d’essai. Il peut être plus simple d’associer un entier à chacun des états et
d’utiliser le type integer pour le port de sortie des états. Cela dépend de la complexité de la machine.
Lors de la synthèse et de l’implémentation de la machine, on n’a qu’à ne pas relier le port d’inspection
des états à un port concret du circuit, ou encore à le placer en commentaires.
7.11
Élaboration d’un plan de test
Un plan de test est un document qui détaille la stratégie employée pour effectuer la vérification d’un système. La complexité et le niveau de détail d’un plan de test dépendent de la taille du module, circuit, soussystème ou système à vérifier.
Un plan de test complet pourrait entre autres détailler:
INF3500 : Conception et réalisation de systèmes numériques
124
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques

la couverture du test: quels requis de la spécification doivent être vérifiés par le test?

les méthodes de test: comment le système sera-t-il vérifié? quelles sont les conditions de réussite et
d’échec des cas de test?

les responsabilités de test: qui est responsable de quels tests?
Un plan de test peut être élaboré en trois étapes :

Extraire les fonctionnalités requises du système, de l’unité ou du module à partir de ses spécifications;

Prioriser les fonctionnalités à vérifier; et,

Créer des vecteurs de test.
7.11.1 Extraire les fonctionnalités requises du système
Une spécification architecturale d’un système décrit son interface avec le monde extérieur et ses relations
d’entrées et sortie sans spécifier comment son comportement interne doit être réalisé.
Extraire toutes les fonctionnalités requises à partir de la spécification est une tâche difficile qui
s’automatise mal, entre autres parce que certaines fonctionnalités sont implicites. D’autres fonctionnalités
ou comportements ne doivent pas être présents, sans que ce soit nécessairement mentionné dans la spécification. On peut regrouper les fonctionnalités à vérifier en quatre catégories :

Il est possible de placer le système dans son état de départ valide à partir de n’importe quel état.

À partir d’un état valide et étant donnée une entrée valide, le système doit se placer dans le bon état
valide.

À partir d’un état valide et étant donnée une entrée valide, le système ne doit pas se placer dans un
état non valide ou un état incorrect.

À partir d’un état valide et étant donnée une entrée non valide, le système ne doit pas se placer dans
un état non valide ou un état incorrect. Le système devrait dans certains cas identifier l’entrée incorrecte et donner un message d’erreur.
7.11.2 Prioriser les fonctionnalités à vérifier
Comme il y a une très grande quantité de fonctionnalités à vérifier, il peut être utile de les prioriser et de
ne vérifier que celles qui correspondent à des contraintes de sécurité et à des besoins fondamentaux du
système et identifiés dans les spécifications. Les fonctionnalités qui faciliteraient l’utilisation du système
peuvent avoir une priorité plus faible. Enfin, les fonctionnalités facultatives ou futures du système peuvent avoir une priorité encore plus faible.
7.11.3 Créer un ensemble de vecteurs de test
Pour chaque fonctionnalité à vérifier, il faut en général choisir un ensemble de vecteurs de test. Il faut
d’abord établir comment vérifier la fonctionnalité, et comment établir qu’elle est satisfaite ou non à partir
des signaux du système. Ensuite, on détermine les vecteurs de test spécifiques qui permettent de stimuler
la fonctionnalité désirée.
Pour aider au processus de création des vecteurs de test, il est nécessaire de bien documenter chaque
étape. Par exemple, dans un tableau on peut identifier les fonctionnalités à vérifier ainsi que leur priorité,
assigner une personne responsable et suivre leur statut dans le temps : en développement, débuté, écrit,
appliqué, révisé, etc.
INF3500 : Conception et réalisation de systèmes numériques
125
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
7.12
Composition d’un ensemble de vecteurs de test
7.12.1 Principes généraux
Le problème de la création d’un ensemble de vecteurs de test n’est pas simple. Comment en effet
s’assurer que les vecteurs de test choisis permettent de bien vérifier que le circuit rencontre ses spécifications? Les tests exhaustifs décrits à la section 7.5.1 sont intéressants parce qu’ils permettent d’observer le
comportement du circuit pour toutes les conditions possibles d’entrée. En pratique, cependant, il est impossible d’effectuer un test exhaustif dans un temps raisonnable.
Par exemple, pour un système avec N bascules, S = 2N états, M entrées et R = 2M transitions possibles
entre les états, il faudrait prévoir 2N + M vecteurs de test différents juste pour effectuer toutes les transitions
possibles du système au moins une fois. Bien qu’on puisse imaginer générer automatiquement un tel ensemble de vecteurs de test, il pourrait s’avérer impossible de tous les appliquer au système en simulation
dans un temps raisonnable.
7.12.2 Qualités d’un bon ensemble de vecteurs de test
Un bon ensemble de vecteurs de test possède les qualités suivantes :

il est efficace pour découvrir des bogues, c’est-à-dire que chaque vecteur de test vérifie plusieurs
fonctionnalités en même temps, et donc que peu de vecteurs de tests sont nécessaires ce qui accélère
le processus de vérification;

il aide à déterminer la source des bogues, ce qui simplifie grandement leur éradication;

il est reproductible, donc il est facile de recréer le bogue;

son application au circuit est automatisée à l’aide d’un banc d’essai; et,

il peut être exécuté dans un temps raisonnable.
Le concept de « temps raisonnable » est bien sûr relatif. Dans le cadre d’un laboratoire de trois heures, un
temps raisonnable serait de l’ordre de quelques minutes. Dans le cadre d’un système développé sur plusieurs semaines, un temps raisonnable serait de l’ordre de quelques heures.
7.12.3 Tests de boîte noire et de boîte blanche
Le terme « test de boîte noire » fait référence à un test qui ne suppose aucune connaissance de
l’implémentation du système. Les tests de boîte noire s’appuient uniquement sur les spécifications du
système. Plus le système est complexe, et plus il faut utiliser ce genre de test. Il est difficile de déterminer
à quel point le système a été vérifié par ce genre de test. Les tests de boîte noire ne permettent pas en général de découvrir des comportements non spécifiés du système.
Le terme « test de boîte blanche » fait référence à un test qui nécessite de connaître le fonctionnement
interne du système. En s’appuyant sur des principes de couverture, on peut calculer des métriques permettant de déterminer à quel point le test a vérifié le système. Les tests de boîte blanche ne permettent pas en
général de découvrir les fonctionnalités manquantes du système.
7.12.4 Vecteurs de test choisis par partitionnement en classes
Ce test est un test de boîte noire.
Cette approche consiste à partitionner l’ensemble des valeurs d’entrée du système en classes séparées. Le
principe du partitionnement en classes s’appuie sur la supposition que deux données d’une même classe
sont similaires et que le comportement du système est semblable pour elles. Pendant le test, on doit choisir des données qui appartiennent à chacune des classes.
INF3500 : Conception et réalisation de systèmes numériques
126
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
La Figure 7-2 illustre le principe du partitionnement en classes pour un système à trois entrées, et pour
lequel le nombre de classes pour chacune des entrées est de 3, 2 et 4 pour les entrées 1, 2 et 3, respectivement.
classe 1-1
Entrée1
classe 1-2
classe 1-3
classe 2-1
Entrée2
Circuit à vérifier
Sortie
classe 2-2
classe 3-1
classe 3-2
Entrée3
classe 3-3
classe 3-4
Figure 7-2 – partitionnement en classes
Un test faible consiste en un ensemble de vecteurs tests où au moins un élément de chacune des classes
serait présent au moins une fois. Dans l’exemple de la Figure 7-2, il faudrait au moins quatre vecteurs de
test pour un test faible.
Un test fort consiste en un ensemble de vecteurs de test où toutes les interactions entre les classes seraient
présentes au moins une fois. Le nombre de vecteurs de test dans ce cas est égal au produit du nombre de
classes pour chacune des entrées du système. Dans l’exemple de la Figure 7-2, il faudrait au moins 24
vecteurs de test pour un test fort.
Par exemple, pour un module de chronomètre qui doit calculer la date du lendemain à la fin de la journée,
on peut identifier les classes de données d’entrée suivantes.

Pour les mois : mois de 30 jours, mois de 31 jours, mois de février.

Pour les jours : jour est entre 1 et 28, jour est 29, jour est 30, jour est 31.

Pour les années : année divisible par 4, année centenaire, autres années.
Pour un test fort, on devrait choisir au moins un vecteur de test pour chacune des combinaisons de classes.
Par exemple, l’ensemble de vecteurs de test devrait inclure le cas du mois de 31 jours avec les quatre
classes de jour et les trois classes d’années. On devrait considérer aussi le cas du mois de février, le jour
31 et l’année centenaire, même si cette combinaison n’est pas une entrée valide.
Il n’est pas facile en général d’énumérer toutes les classes de données possibles. La combinaison de vecteurs de test couvrant toutes les combinaisons de classes peut être très grande.
7.12.5 Vecteurs de test choisis par analyse des valeurs limites
Ce test est un test de boîte noire.
Les erreurs se produisent souvent aux valeurs limites des données. Par exemple, pour une addition, il est
nécessaire de vérifier si un débordement peut se produire. L’analyse des valeurs limites permet
d’identifier les combinaisons possibles de données à vérifier.
INF3500 : Conception et réalisation de systèmes numériques
127
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
On devrait par exemple inclure dans les vecteurs de test, pour chaque donnée : sa valeur minimale, une
valeur juste inférieure à la valeur minimale (si c’est possible), une valeur juste supérieure à sa valeur minimale, sa valeur nominale, sa valeur maximale, une valeur juste inférieure à la valeur maximale, et une
valeur juste supérieure à sa valeur maximale (si c’est possible). Cela fait jusqu’à sept valeurs différentes à
vérifier pour chaque donnée.
Si le nombre de variables n’est pas trop grand, on devrait vérifier toutes les combinaisons possibles des
valeurs limites de chacune des variables. Dans le cas discuté au paragraphe précédent, cela représenterait
7n cas différents pour n variables. Si le nombre de variables est trop grand, on peut éliminer les valeurs
interdites (sous le minimum et en haut du maximum) et on obtient alors 5n cas différents. On peut encore
réduire le nombre de combinaisons en fixant toutes les variables à leur valeur nominale, sauf une à la fois
qui passe à travers toutes ses valeurs limites.
7.12.6 Vecteurs de test pseudo-aléatoires
Ce test est un test de boîte noire.
Ce genre de test a été considéré à l’Exemple 7-4. Les vecteurs de test pseudo-aléatoires ont l’avantage
d’être simples à générer. Ils peuvent compléter de façon intéressante un ensemble de vecteurs de tests
composé avec une autre méthode.
Quelques principes doivent être respectés pour les tests pseudo-aléatoires :

Il est utile de distinguer entre des valeurs valides et non valides appliquées au système, et s’assurer de
générer surtout des valeurs de test valides.

Le test doit être reproductible, donc il faut choisir des valeurs de graines connues (et non la valeur de
l’horloge) pour lancer la génération des nombres pseudo-aléatoires.

Le test devrait avoir un objectif précis en restreignant les valeurs aléatoires générées à une classe.

La distribution des valeurs aléatoires devrait être connue et contrôlable pour correspondre aux conditions d’opération du système.
7.12.7 Couverture de code
Ce test est un test de boîte blanche.
Dans la couverture de code, on choisit des vecteurs de test pour exercer un élément particulier du design
ou de sa description. Il y en a plusieurs :

Couverture d’énoncés : pourcentage des énoncés du code exécutés.

Couverture de blocs : pourcentage de blocs d’énoncés délimités par des structures de contrôle qui ont
été exécutés. Cette métrique a l’avantage d’être plus représentative que la couverture d’énoncés, parce
que les blocs comportant plusieurs énoncés n’ont pas un poids plus important que les autres.

Couverture de branchements : pourcentage des choix d’un branchement ayant été exécutés.

Couverture d’expressions : pourcentage des composantes des expressions booléennes qui ont affecté
la valeur de ces expressions.

Couverture d’états : pourcentage du nombre d’états visités.

Couverture de transitions : pourcentage des transitions de chaque état ayant été prises.

Couverture de changements de signaux : pourcentage de signaux binaires ayant passé de 0 à 1 et de 1
à 0.
INF3500 : Conception et réalisation de systèmes numériques
128
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
Pour chacune des couvertures possibles, on peut calculer une métrique qui exprime soit le nombre de fois
que chaque situation se produit, ou encore le pourcentage des situations qui se sont produites par rapport
au nombre total de situations possibles. Par exemple, on voudrait atteindre 100% de couverture des énoncés. Si on n’est qu’à 90%, cela signifie qu’il faut stimuler le circuit avec d’autres vecteurs de test.
Pour calculer ces métriques, le code doit être instrumenté de façon à extraire des statistiques. Heureusement, des outils de design existent pour faire ce traitement automatiquement. De plus, ces mêmes outils
peuvent présenter l’information obtenue de façon conviviale ce qui permet de faciliter la sélection de
vecteurs de test.
Les différents éléments de couverture ne sont pas tous indépendants. Par exemple, la couverture d’états et
la couverture de transition sont effectivement des sous-ensembles de la couverture d’énoncés et de branchements.
7.12.8 Création de vecteurs de test selon la couverture de code
Un bon ensemble de vecteurs de tests devrait résulter en une couverture de code de 100%. Même si toutes
les métriques de couverture sont à 100% pour ensemble de vecteurs de test, cela ne signifie pas que le
circuit rencontre toutes ses spécifications. Cependant, les métriques de couverture de code viennent compléter les autres types de tests et donnent une certaine assurance au concepteur que le circuit est bien vérifié.
Il peut y avoir des exceptions, comme par exemple des énoncés qui sont en place pour protéger le système
lors d’entrées non valides, ou pour ramener le système dans un état valide à partir d’un état non valide.
Dans le premier cas, cependant, on devrait créer un ensemble de vecteurs de test pour vérifier ce genre de
situation. Dans le deuxième cas, il devrait être impossible de placer le système dans cet état non valide.
7.12.9 Couverture de paramètres d’opération
Ce test est un test de boîte blanche.
Une limite importante de la couverture de code est qu’elle n’indique que si certaines situations ont été
exercées ou non, sans égard réel à la fonctionnalité du système.
Un test plus puissant consiste à identifier les paramètres d’opération du système et à vérifier la couverture
des valeurs possibles de ceux-ci. Par exemple, pour une file d’attente, un paramètre serait le nombre
d’éléments dans la file. Il est important de vérifier l’opération de la file quand celle-ci est vide, presque
vide, pleine et presque pleine, ainsi qu’en situations mitoyennes.
Pour obtenir la couverture des paramètres d’opération, les étapes suivantes peuvent être suivies :

Énumérer les paramètres d’opération du module;

Pour chaque paramètre, déterminer la gamme des valeurs possibles et identifier les valeurs qui doivent absolument être vérifiées et dans quelles circonstances;

Instrumenter le code ou le banc d’essai afin de noter les valeurs de paramètre utilisées;

Simuler le système; et,

Calculer le rapport des valeurs utilisées sur le nombre de valeurs totales possible et établir si les valeurs à vérifier l’ont été.
7.12.10
Couverture fonctionnelle
Dans ce genre de couverture, on énumère toutes les fonctions que le système doit pouvoir effectuer. Par
exemple, dans un processeur, il doit être possible de transférer la valeur d’un registre vers un autre. On
doit donc choisir des vecteurs de test qui exercent chacune des fonctions de la spécification.
INF3500 : Conception et réalisation de systèmes numériques
129
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
7.13
Concepts avancés de vérification
7.13.1 Analyse statique du code
La meilleure façon de réduire le nombre de bogues dans un design est de réduire les chances de leur introduction dans celui-ci. En adoptant des pratiques de codage favorisant la vérification, on augmente les
chances d’atteindre ce but. Les guides de codage sont souvent développés avec le temps en se basant sur
l’expérience des concepteurs. Les guides de codage tendent à restreindre l’utilisation d’un langage à un
sous-ensemble plus robuste, plus sécuritaire.
Il existe des outils de vérification du respect des guides de codage qui effectuent une analyse statique du
code. Le premier programme de la sorte s’appelait ‘lint’, et ce terme est souvent appliqué aux outils
comme au processus.
En VHDL et dans les autres HDL, une analyse statique peut détecter des erreurs potentielles et augmenter
la qualité du code. Ces erreurs potentielles peuvent se situer à plusieurs niveaux, et la liste suivante donne
quelques exemples :

Opérandes de largeurs différentes dans une expression;

Énoncés conditionnels dont tous les cas ne sont pas couverts et qui créent des états implicites;

Énoncés conditionnels qui se recoupent;

Nom d’entité différent du nom du fichier;

Insertion de signaux de contrôle dans le chemin d’une horloge;

Signaux ou variables qui ne sont pas initialisés avant d’être utilisés;

Signaux ou variables auxquels on n’assigne jamais de valeur ou qui ne sont jamais utilisés; et,

Expression constante dans une structure de condition.
7.13.2 Vérification hiérarchique
Pour simplifier l’effort de vérification, il est utile d’adopter une approche hiérarchique. Cette approche
devrait correspondre à la hiérarchie naturelle du système, qui devrait avoir été appliquée pour en simplifier l’effort de conception. Une hiérarchie possible peut avoir trois niveaux : le module, l’unité et le système.
Au niveau des modules comme un additionneur ou un décodeur, la vérification peut-être faite directement
selon la spécification et parfois par un test exhaustif. On a toute la visibilité de l’intérieur du module. Le
comportement attendu est relativement simple.
Au niveau des unités, comme par exemple une UAL d’un processeur, on peut choisir des vecteurs de test
à partir des spécifications. On a une bonne visibilité de l’interface entre les modules. La vérification doit
porter beaucoup sur les interactions entre les modules.
Au niveau du système, en plus de vérifier des fonctionnalités de haut niveau, on doit vérifier que les interconnections entre les unités sont correctes. On ne peut pas en général exploiter la visibilité de l’intérieur
du système.
[La terminologie adoptée ici varie un peu de celle du génie logiciel :

tests unitaires pour les modules atomiques;

tests d’intégration pour des groupes de modules; et,

tests de système pour le système au complet.]
INF3500 : Conception et réalisation de systèmes numériques
130
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
7.13.3 Détection, identification et suivi des bogues
Le but de la sélection des vecteurs de test et leur application au circuit en simulation est de découvrir les
bogues de celui-ci. Quand un bogue survient, trois étapes doivent être suivies.
Tout d’abord, il faut identifier les conditions où le bogue est devenu apparent en documentant la version
du code qui est en vérification, la suite de vecteurs de tests qui a mené à la défaillance, et les paramètres
de simulation.
Ensuite, il faut déterminer la source du bogue. Cela peut nécessiter de réduire la portée du circuit ou de
l’ensemble de vecteurs de test. Plus il est possible d’identifier exactement dans quel module ou à quelle
ligne se situe l’origine d’un bogue et plus facile sera son élimination. En réduisant la taille du circuit qui
est simulé et qui présente toujours la défaillance, on se simplifie grandement la vie. Similairement, si on
peut simplifier l’ensemble de vecteurs de test qui provoque la défaillance, il est plus facile de comprendre
la nature du problème.
Finalement, il est important de documenter les bogues dans un système de suivi. Un tel système a tout
d’abord pour but de s’assurer qu’aucun bogue n’est oublié. Le statut de chaque bogue est bien identifié
ainsi que les actions prises pour le résoudre. Les bogues peuvent de plus être priorisés pour systématiser
l’élaboration d’un plan d’attaque pour les résoudre. Finalement, un graphique de la fréquence d’apparence
de nouveaux bogues dans un système donne une indication générale de la fiabilité de celui-ci.
7.14
Exercices
1. Un circuit combinatoire a n entrées. Combien de cas possibles doivent être considérés pour faire un
test exhaustif?
2. Résumer, sous forme de tableau, les cas les plus appropriés où l’on devrait utiliser un tableau de constantes, une vérification aléatoire, une vérification exhaustive et des entrées-sorties par fichier pour un
banc d’essai.
3. Écrire un banc d’essai en VHDL pour chacun des modules VHDL demandés en exercice à la section
2.6.
4. Considérez le code VHDL suivant pour un module combinatoire et son banc de test associé.
library IEEE;
use IEEE.std_logic_1164.all;
entity module1 is
port (
A, B : in std_logic;
F : out std_logic
);
end module1;
architecture arch of module1 is
signal S1, S2: std_logic;
begin
S1 <= A and B;
S2 <= not(B);
process (S1, S2)
begin
F <= S1 xor S2;
end process;
end arch;
library IEEE;
use IEEE.std_logic_1164.all;
entity module1TB is
end module1TB;
architecture arch of module1TB is
component module1
port (
A, B : in std_logic;
F : out std_logic
);
end component;
signal A,B,F : std_logic;
begin
UUT : module1 port map (A, B, F);
A <= '0' after 0 ns;
B <= '1' after 0 ns, '0' after 10 ns;
end arch;
a. Donnez la liste des événements à partir du temps de simulation 10 ns, telle qu’elle pourrait être dressée
par un simulateur qui exécuterait le banc d’essai.
b. En vous basant sur votre liste des événements, donnez un chronogramme à partir du temps de simulation 10 ns, montrant la valeur des signaux internes et de sortie en tenant compte des délais deltas.
INF3500 : Conception et réalisation de systèmes numériques
131
v. 2.5, juillet 2013
Chapitre 7 : Vérification de circuits numériques
5. Élaborez un plan de test pour chacun des modules VHDL demandés en exercice à la section 5.6.
6. Élaborez un plan de test pour l’exemple du multiplicateur de la section 6.6.
7. Élaborez un plan de test pour l’exemple du joueur de blackjack de la section 6.7.
8. Élaborez un plan de test pour chacun des modules VHDL demandés en exercice à la section 6.8.
INF3500 : Conception et réalisation de systèmes numériques
132
v. 2.5, juillet 2013
Chapitre 8
8.1
Considérations pratiques
Introduction
La réalisation d’un circuit séquentiel implique plusieurs considérations pratiques. Les chapitres précédents concernaient la conception d’un circuit rencontrant des spécifications fonctionnelles, c'est-à-dire en
rapport avec des relations d’entrées-sorties. Le danger pour le concepteur est de faire abstraction des considérations pratiques d’implémentation d’un circuit séquentiel, et d’obtenir un circuit qui ne fonctionne
qu’en simulation. Pour la réalisation d’un circuit séquentiel, il faut tenir compte d’autres aspects des spécifications.
On s’intéresse en premier à la fréquence maximale de l’horloge du circuit, qui permet de déduire le taux
de traitement maximum des données. Les deux ne sont pas nécessairement égaux. En effet, un processeur
peut nécessiter plusieurs cycles d’horloge pour traiter une seule donnée. On s’intéresse aussi aux problèmes de synchronisation entre systèmes qui ne partagent pas une horloge commune, et au problème de
la saisie d’événements ponctuels comme commandes des êtres humains.
Ce chapitre discute de plusieurs considérations pratiques concernant la réalisation de circuits séquentiels
synchrones spécifiquement en logique programmable et sur FPGA en particulier.
À l’exception des questions d’interface, le chapitre concerne uniquement les systèmes synchrones. Par
système synchrone on veut dire un système qui comporte une horloge de référence. C’est le type circuit
séquentiel le plus commun. Les circuits synchrones sont plus fiables. Ils sont surtout plus simples à concevoir, vérifier et tester que les circuits asynchrones.
8.2
Paramètres de synchronisation
8.2.1
Transitions sur les signaux
Dans les circuits logiques, les signaux intermédiaires et de sortie peuvent entrer en transition quand les
signaux d’entrée changent. Par exemple, pour un inverseur, quand l’entrée passe de 1 à 0, la sortie doit
passer de 0 à 1. Ces transitions ne se font pas instantanément.
On définit les paramètres suivants pour quantifier les transitions sur les signaux :

temps de descente (fall time – tf) : le temps nécessaire au signal pour passer de 90% à 10% de sa valeur maximale;

temps de montée (rise time – tr) : le temps nécessaire au signal pour passer de 10% à 90% de sa valeur
maximale;

délai de descente (propagation delay, High to Low – tPHL) : le temps écoulé entre un changement sur
un signal d’entrée et un changement correspondant de 1 à 0 du signal de sortie, mesuré aux points de
50% d’intensité des deux signaux; et,

délai de montée (propagation delay, Low to High – tPLH) : le temps écoulé entre un changement sur un
signal d’entrée et un changement correspondant de 0 à 1 du signal de sortie, mesuré aux points de
50% d’intensité des deux signaux.
Ces paramètres sont influencés en général par trois critères :

la charge capacitive à mener (dépend du nombre de composantes menées par le circuit ainsi que la
longueur des interconnexions);

la résistance des conducteurs (dépend surtout de la longueur des interconnexions); et,

la dimension des transistors.
INF3500 : Conception et réalisation de systèmes numériques
133
v. 2.42, décembre 2009
Chapitre 8 : Considérations pratiques
Une plus grande charge capacitive et une plus grande résistance des conducteurs signifient que les transistors du circuit auront plus de difficulté à effectuer des transitions sur la sortie du circuit, soit pour charger
les condensateurs (transition 0 à 1) ou les décharger (transition 1 à 0). Plus les transistors peuvent mener
du courant, plus le circuit sera rapide.
8.2.2
Délai de propagation d’une composante
Le délai de propagation d’une composante indique le temps nécessaire pour que la sortie de la composante se stabilise suite à un changement à l’une de ses entrées. Pour les composantes séquentielles comme
les bascules et les loquets, on mesure en général le délai de propagation à partir de la transition de
l’horloge. Le symbole pour le délai de propagation varie selon les auteurs et le type de composante. On
utilise souvent td pour les bascules et loquets, et tcomb pour la logique combinatoire. La valeur du délai est
en général calculée par le maximum des temps de montée et de descente, qui sont souvent différents.
La mesure du délai de propagation suppose que les transitions sur les entrées respectent certaines contraintes dans le temps. On suppose souvent que les transitions sont idéales, c'est-à-dire que la pente du
signal est infinie lors d’une transition (et donc que les temps de montée et de descente sont nuls), ce qui
n’est jamais vrai en pratique.
Le délai de propagation maximal d’une composante est en général spécifié par le manufacturier pour des
conditions d’opération données. Ces conditions d’opération peuvent inclure :

la tension d’alimentation;

la température; et,

la charge menée par la composante.
La figure Figure 8-1 illustre le chronogramme d’une composante combinatoire.
td
A
A
B
C
composante
td
td
td
td
B
F
C
F
valeur inconnue
Figure 8-1 – délai de propagation
8.2.3
Délai de propagation des interconnexions
Le délai de propagation du aux interconnexions dépend surtout de leur longueur et du matériau dans lequel elles sont fabriquées. Ces deux facteurs influent sur leur charge capacitive et sur leur résistance.
Quand les délais des composantes sont très grands, on peut parfois négliger les délais de propagation dus
aux interconnexions.
INF3500 : Conception et réalisation de systèmes numériques
134
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
8.2.4
Bascules et loquets : temps de préparation et de maintien
Pour qu’une bascule ou un loquet fonctionne correctement, il faut que le signal d’entrée soit stable pendant une période définie avant et après la transition active de l’horloge.
Le temps de préparation (setup time – tsu) est le temps minimal pendant lequel le signal d’entrée de la
bascule ou du loquet ne doit pas changer avant la transition active de l’horloge.
Le temps de maintien (hold time – th) est le temps minimal pendant lequel le signal d’entrée de la bascule
ou du loquet ne doit pas changer après la transition active de l’horloge.
La Figure 8-2 illustre une situation où les temps de préparation et de maintien sont respectés pour une
bascule D activée sur une transition positive de l’horloge.
temps de
préparation tsu
D
Q
CLK
D
CLK
temps de
maintien th
signal stable
Q
valeur précédente
valeur courante
délai de propagation Td
Figure 8-2 – respect des temps de préparation et de maintien
Si le temps de préparation ou le temps de maintien ne sont pas respectés, alors la bascule ou le loquet
risquent d’entrer dans un état métastable, c'est-à-dire que leur sortie aura un niveau imprévisible entre 0 et
1. En théorie, l’élément à mémoire pourrait rester dans l’état métastable indéfiniment. En pratique, il finit
par se stabiliser sur un des deux états après un certain temps difficile à estimer.
8.3
Fréquence maximale d’opération et chemin critique
La fréquence maximale d’opération d’un circuit séquentiel correspond à la réciproque de la période minimale de son horloge, pour laquelle le circuit continue de produire des résultats corrects.
f max 
1
Tmin
Pour déterminer la période minimale d’un circuit séquentiel, on énumère tous les chemins possibles entre
chaque paire de bascules. On mesure ensuite le délai sur chacun de ces chemins en tenant compte des
délais des composantes, des délais de propagation et du temps de préparation de la bascule qui reçoit le
signal. Le chemin critique est le chemin ayant le plus long délai. La période minimale du circuit est égale
à la somme du délai sur le chemin critique et du temps de préparation de la bascule qui reçoit le signal.
Cette relation est indiquée par l’équation suivante :
Tmin  td  tcomb  t prop  tsu
où td est le délai de propagation de la bascule source, tcomb est le délai de propagation de la logique combinatoire sur le chemin, tprop est le délai de propagation sur les interconnexions, et tsu est le temps de préparation de la bascule de destination. Cette équation suppose que les deux bascules reçoivent des fronts
d’horloge parfaitement synchronisés.
Pour un circuit qui opère à une fréquence d’horloge donnée inférieure à la fréquence maximale, on définit
la marge libre de préparation (setup-time margin) comme T – Tmin, où T est la période de l’horloge.
INF3500 : Conception et réalisation de systèmes numériques
135
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
En guise d’exemple, considérons la Figure 8-3. Supposons que les bascules ont un temps de préparation
de 1 ns et un délai de propagation de 2 ns. Supposons que les portes logiques INV, ET, OU et OUX ont
des délais de propagation de 1, 2, 2 et 3 ns, respectivement. Supposons de plus qu’on peut négliger les
délais de propagation des interconnexions. Dans ce cas, le chemin critique est B – INV – OUX – OU – F
et la période minimale est 2 + 1 + 3 + 2 + 1 = 9 ns.
D Q
A
D Q
CLK
B
D Q
CLK
F
D Q
CLK
C
CLK
Figure 8-3 – chemin critique – exemple #1
Le déphasage d’horloge
8.4
Nous avons supposé à date que toutes les bascules du circuit recevaient un signal d’horloge idéal et cela
simultanément, c'est-à-dire que les fronts de l’horloge arrivaient à chaque bascule sans aucun déphasage.
En pratique, ce n’est jamais le cas et il y a toujours un certain déphasage d’horloge (clock skew).
8.4.1
Causes du déphasage d’horloge
Il y a trois façons par lesquelles un déphasage d’horloge peut être introduit entre les bascules.

un mauvais routage du signal d’horloge avec des chemins de longueur différente;

un mauvais routage du signal d’horloge avec un débalancement de la charge du signal; et,

contrôle du signal d’horloge avec de la logique combinatoire (clock gating).
8.4.2
Conséquences du déphasage d’horloge
Cas #1. Le déphasage d’horloge peut augmenter la marge libre de préparation si la bascule qui reçoit le
signal en provenance d’une autre bascule reçoit aussi un signal d’horloge retardé. Comme le front
d’horloge arrive en retard, ce retard vient compenser les délais de propagation le long du chemin entre les
deux bascules. La période d’horloge pourrait donc être diminuée. On a alors :
T  t d  tcomb  t prop  t su  tCS
(8-1)
où tCS est le déphasage d’horloge. On suppose ici que le déphasage d’horloge est positif, c'est-à-dire que
la bascule qui reçoit le signal a une horloge en retard par rapport à la bascule source.
Cas #2. Dans le cas où les délais de propagation sont très courts, le déphasage d’horloge peut mener à un
non respect du temps de maintien. En effet, il faut que le signal à l’entrée de la bascule de destination
reste stable suffisamment longtemps par rapport au front d’horloge qui l’alimente. L’inéquation suivante
doit en fait être respectée :
t d  tcomb  t prop  tCS  t h
(8-2)
Cas #3. Un déphasage d’horloge négatif est aussi possible, c'est-à-dire que la bascule source a une horloge qui est en retard par rapport à la bascule qui reçoit le signal. Dans ce cas, la période minimale du
circuit doit être augmentée, en conformité avec l’équation (8-1). Selon le circuit, on peut parfois modifier
l’analyse en considérant un déphasage d’horloge positif égal à la somme de la période de l’horloge et du
déphasage (négatif) constaté.
INF3500 : Conception et réalisation de systèmes numériques
136
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
Synchronisation entre domaines d’horloge différents
8.5
La plupart des systèmes numériques réels acceptent des entrées du monde extérieur, et ces entrées sont
manifestement asynchrones. Par exemple, un ascenseur doit pouvoir correctement interpréter les signaux
en provenance des boutons du panneau de contrôle. Les systèmes numériques doivent aussi pouvoir
communiquer entre eux sans nécessairement partager une horloge commune. Par exemple, un ordinateur
doit pouvoir correctement interpréter des signaux en provenance d’un clavier ou d’une souris. Ces dispositifs sont dotés de leur propre générateur d’horloge.
Le problème d’interfaçage dans ces cas est le suivant : comment s’assurer que les transitions sur les signaux provenant de l’autre système ou du monde extérieur ne se produisent pas à l’intérieur de la période
définie par les paramètres tsu et th autour des fronts actifs d’horloge?
Une solution habituelle consiste à utiliser deux bascules connectées en cascade, tel que montré à la Figure
8-4. Dans ce circuit, la première bascule est reliée à la source asynchrone. Son signal de sortie, Smeta, peut
être métastable. En supposant que la source asynchrone et l’horloge du système n’ont aucune corrélation,
la probabilité que la première bascule soit métastable est égale à (tsu + th) / T, où T est la période d’horloge
du système. Si la première bascule entre dans un état métastable, elle finira en pratique par se stabiliser
sur un 0 ou un 1. La deuxième bascule permet d’accorder le plus long temps possible à la première pour
se stabiliser, soit une période d’horloge.
Il est possible d’augmenter la performance du circuit de synchronisation en augmentant le nombre de
bascules dans la chaîne, ou encore en alimentant la deuxième bascule avec une horloge plus lente. Cependant, dans ce cas on introduit habituellement un déphasage d’horloge qui doit ensuite être compensé.
Dans le circuit du double tampon, on suppose que la fréquence d’horloge du système synchrone est beaucoup plus grande que la fréquence avec laquelle varie la sortie de la source asynchrone, et donc qu’on
l’échantillonne suffisamment souvent.
source
asynchrone
Sasync
Smeta
D Q
Ssync
D Q
système synchrone
CLK
CLK
CLK
Figure 8-4 – double tampon
8.6
Optimisation d’un design pour la surface ou le débit
8.6.1
Distinction entre latence et débit
Dans le domaine des systèmes numériques et de l’architecture des ordinateurs, on utilise souvent le terme
« vitesse » de façon incorrect. Par « vitesse » d’exécution on veut souvent dire l’une de deux choses : la
latence ou le débit du système. On parle souvent aussi de la « vitesse » d’un processeur en voulant dire sa
fréquence d’horloge.
La latence est le temps nécessaire entre le moment où une donnée est disponible et le moment où le résultat qui dépend de cette donnée est disponible à son tour. La latence est souvent exprimée en nombre de
cycles d’horloges. On obtient le temps correspondant en multipliant le nombre de cycles par la période
d’horloge, donc une fréquence d’horloge plus élevée correspond en général à une latence plus courte.
Le débit est le nombre de résultats qui sont produits par unité de temps ou par cycle d’horloge. Quand le
débit est inférieur à un résultat par cycle, on utilise plutôt la réciproque du débit comme métrique : le
INF3500 : Conception et réalisation de systèmes numériques
137
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
nombre de coups d’horloges nécessaires pour produire un résultat. Quand on calcule le débit, on suppose
qu’une quantité suffisante de données est disponible à l’entrée du système. Une fréquence d’horloge plus
élevée peu correspondre à un débit plus grand, mais le nombre d’unités de traitement qui opèrent en parallèle doit aussi être considéré.
8.6.2
Maximiser le débit
Pour maximiser le débit, on doit augmenter le nombre de calculs effectués par unité de temps. Pour ce
faire, on peut augmenter la fréquence d’horloge ou augmenter le nombre de calculs effectués à chaque
coup d’horloge.
Pour augmenter la fréquence d’horloge, il faut réduire le délai sur le chemin critique du circuit. Une façon
efficace de réduire ce délai est de briser le chemin critique en deux en y insérant des registres de pipeline.
Pour augmenter le nombre de calculs effectués à chaque coup d’horloge, on peut paralléliser les calculs
en instanciant plusieurs unités de calcul identiques qui traitent des données différentes en parallèle. Par
exemple, pour un processeur vidéo, on peut parfois décomposer une image en régions indépendantes et
associer le traitement de chaque région à un processeur différent.
8.6.3
Exemple : architecture à pipeline
L’utilisation d’architectures à pipeline est une technique extrêmement puissante pour augmenter la fréquence d’horloge d’un système et son débit. On se rappelle que la période minimale de l’horloge est donnée par :
Tmin  td  tcomb  t prop  tsu
Pour diminuer Tmin, il faut réduire la somme des termes. Le délai et le temps de préparation des bascules
est en général fixe. On peut réduire le temps de propagation en réduisant la longueur des interconnexions,
ce qui requiert parfois un effort important au moment de la disposition des composantes du circuit. Une
architecture à pipeline s’attaque aux délais de la logique combinatoire en décomposant le chemin critique.
Considérons le circuit montré à la Figure 8-5. On observe que le chemin critique pour ce circuit va de la
bascule 3 vers la bascule 4, en passant par deux portes OUX. En supposant que les bascules ont un temps
de préparation de 1 ns et un délai de propagation de 2 ns, la période minimale du circuit est de 11 ns.
En introduisant des bascules à l’intérieur de la partie combinatoire, on peut grandement diminuer la période minimale, tel que montré à la Figure 8-6.
Dans le circuit avec pipeline, il y a maintenant deux chemins critiques égaux, avec une période minimale
d’horloge résultante de 7 ns, soit une réduction de 36%. En pratique, même si on brise exactement un
long chemin critique en deux, on n’atteint pas une réduction de 50%. La raison est qu’on ne peut pas éliminer le délai de propagation et le temps de préparation des bascules. Dans le circuit de la Figure 8-6,
même si on parvenait à décomposer les portes logiques existantes, on ne réussirait jamais à réduire la
période minimale sous 3 ns.
Dans le circuit avec pipeline, les sorties du système arrivent maintenant avec un cycle d’horloge de retard.
Cela peut être ou non acceptable, selon la situation. Par exemple, dans le cas d’un lecteur audio, le fait
d’avoir quelques cycles de retard est sans importance. En supposant un taux de données de 44.1 KHz, la
durée de 10 cycles d’horloge est inférieure à 250 μs. Ce retard est imperceptible pour un être humain qui
vient de lancer la lecture d’un fichier de musique. De façon similaire, les retards inférieurs à quelques
secondes pour la projection d’un flux vidéo est sans importance. Il y a pourtant des applications ou un
pipeline peut causer des délais inacceptables, comme par exemple dans les communications téléphoniques. Si le délai de transmission excède un dixième de seconde, il devient perceptible et est désagréable.
INF3500 : Conception et réalisation de systèmes numériques
138
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
Le désavantage principal d’une architecture avec pipeline est son coût élevé en matériel. En effet, quand
on introduit un étage de pipeline il faut synchroniser tous les signaux de cet étage, même s’ils ne sont pas
dans le chemin critique. On voit un exemple de ce fait dans la Figure 8-6 pour le signal émanant de la
bascule 3 vers la porte NON-OU. Les coûts en bascules peuvent rapidement devenir énormes. Cependant,
pour les FPGAs, la présence d’une très grande quantité de bascules prédéfinies à l’intérieur des blocs de
logique programmable rend l’utilisation d’architectures à pipeline des plus intéressantes.
D Q
D Q
1
CLK
3 ns
4 ns
4
CLK
D Q
2
CLK
D Q
3
D Q
4 ns
2 ns
CLK
5
CLK
Figure 8-5 – circuit lent sans pipeline
En ajoutant des niveaux de pipeline, il est important de bien balancer les nouveaux chemins. La fréquence
maximale d’opération du circuit est limitée par le chemin le plus lent du circuit. Il est donc inutile d’avoir
des pipelines non balancés, où des portions ont des délais très courts et d’autres très longs.
D Q
D Q
1
CLK
3 ns
D Q
P1
CLK
4 ns
4
CLK
D Q
2
CLK
D Q
D Q
3
4 ns
CLK
CLK
D Q
P2
2 ns
5
CLK
D Q
P3
CLK
Figure 8-6 – circuit plus rapide avec pipeline
INF3500 : Conception et réalisation de systèmes numériques
139
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
8.6.4
Minimiser la latence
Certains processeurs ne traitent pas un flux important de données, mais traitent plutôt des données ponctuelles à intervalles irréguliers. Dans un tel cas, il est plus important de réduire la latence que le débit.
Pour réduire la latence, on peut réduire le délai sur le chemin critique au maximum sans augmenter le
nombre de cycles d’horloge nécessaires pour effectuer un calcul. On ne veut donc pas considérer une
architecture à pipeline.
On peut aussi répartir certains calculs sur plusieurs unités.
La façon de répartir les calculs peut aussi avoir une incidence importante sur la latence. Par exemple,
considérons le problème qui consiste à additionner quatre nombres. Dans une première version, montrée à
la Figure 8-7, on utilise trois additionneurs en série. Le code VHDL correspondant est Somme <= A +
B + C + D. Le chemin critique est formé de ces trois additionneurs.
A
B
C
Somme
D
Figure 8-7 – addition de quatre nombres, version sérielle
Dans une version améliorée, montrée à la Figure 8-8, le délai sur le chemin critique est réduit de 33% et
ne compte plus que deux additionneurs. Somme <= (A + B) + (C + D). Il n’y a aucun effet sur
la surface du circuit.
A
B
Somme
C
D
Figure 8-8 – addition de quatre nombres, version parallélisée
Une autre approche pour minimiser la latence consiste à éviter d’indiquer des priorités dans les structures
de sélection avec des énoncés elsif. Les structures de sélection se synthétisent habituellement sous la
forme de multiplexeurs. Quand un ordre de priorité est inféré, des portes logiques doivent être ajoutées
dans le chemin de contrôle du multiplexeur. Si toutes les possibilités de la structure de sélection sont exclusives, il est de loin préférable d’utiliser un énoncé case à la place.
INF3500 : Conception et réalisation de systèmes numériques
140
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
8.6.5
Minimiser la surface
Pour minimiser la surface utilisée, on peut tout d’abord utiliser le partage des ressources. Par exemple,
pour implémenter l’extrait de code de l’Exemple 8-1, il y a deux possibilités, montrées à la Figure 8-9. La
différence entre les deux est basée sur la sélection d’une somme ou d’un opérande. Le chemin critique est
le même entre les deux, mais la version de droite n’utilise qu’un seul additionneur.
process (D1, D2, D3, S)
begin
if S = '1' then
D5 <= D1 + D2;
else
D5 <= D1 + D3;
end if;
end process;
Exemple 8-1 – partage de ressources : code VHDL
D1
D2
D1
D5
D5
D2
D3
D3
S
S
Figure 8-9 – partage de ressources : deux possibilités
Une autre approche consiste à utiliser des stratégies contraires à celles utilisées pour maximiser le débit en
éliminant le parallélisme dans les calculs. Au lieu d’instancier plusieurs composantes identiques pour
effectuer des calculs, on n’en utilise qu’une seule et on en contrôle l’accès à l’aide d’une unité de contrôle
qui implémente une machine à états.
8.6.6
Niveaux de compromis de design et leur impact
En règle générale, plus une décision de design est prise à un haut niveau d’abstraction et plus son impact
sera grand sur la performance et la surface d’un système.
Par exemple, le choix de l’algorithme pour effectuer une tâche a l’impact le plus important.
Le choix de la façon d’implémenter l’algorithme, par exemple par une architecture parallèle qui maximise
le débit ou bien une architecture sérielle pour en réduire la surface a un impact très important.
Le choix de la précision des calculs pour implémenter l’algorithme a un impact important.
Le choix des circuits pour effectuer les calculs, par exemple en prenant un additionneur plus rapide mais
plus grand, a un certain impact.
Une bonne décision prise à un bas niveau d’abstraction ne peut pas en général compenser pour une mauvaise décision prise à un haut niveau d’abstraction.
INF3500 : Conception et réalisation de systèmes numériques
141
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
8.7
Génération de signaux d’horloge
8.7.1
Sources d’oscillations
Un générateur d’horloge a comme base un oscillateur. Afin d’obtenir une fréquence de résonnance précise, on utilise en général un cristal résonnant. Cela rend l’oscillateur moins sensible aux variations de
température.
Afin de générer une onde carrée comme signal d’horloge, on utilise un circuit spécial appelé multivibrateur astable.
8.7.2
Génération à partir d’une horloge de référence
En général, il est difficile ou impossible d’ajuster la fréquence d’une source d’oscillations directement.
Pourtant, on a souvent besoin de plusieurs fréquences différentes, comme par exemple dans les circuits de
télévision. On doit alors se servir d’une horloge de référence fixe et générer différents signaux de fréquences inférieures. Un des circuits numériques qui permet d’effectuer cette transformation s’appelle un
synthétiseur numérique d’horloge. Un tel circuit est montré à la Figure 8-10.
Le circuit est en fait un accumulateur, composé d’un additionneur et d’un registre à N bits. L’entrée de
l’accumulateur est un mot de contrôle k permettant de varier la fréquence de sortie, qui est donnée par :
f clk _ out 
fo  k
2N
où f0 est la fréquence de l’horloge de référence.
Le code VHDL correspondant à ce circuit est donné à l’Exemple 8-2. Dans cette description, les différents paramètres du circuit ont été spécifiés sous la forme d’énoncés generic. Au lieu de spécifier la
valeur du mot de contrôle k, on spécifie plutôt la valeur de la fréquence de sortie désirée. Un énoncé
assert informe l’utilisateur, lors de la simulation, si la valeur des paramètres ne permet pas d’obtenir
une précision suffisante de la fréquence de l’horloge de sortie.
accumulateur
/
N
registre
additionneur
mot de contrôle k
bit le plus significatif:
signal d’horloge synthétisé
horloge de référence fo
Figure 8-10 – synthétiseur numérique
INF3500 : Conception et réalisation de systèmes numériques
142
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity clockgen is
generic (
N : positive := 4; -- nombre de bits de l'accumulateur
fClkRef : real := 100.0; -- la fréquence de l'horloge de référence, en Hz
fClkOut : real:= 6.25 -- la fréquence d'horloge désirée, en Hz
);
port(
clkRef : in STD_LOGIC;
clkOut : out STD_LOGIC
);
end clockgen;
architecture clockgen of clockgen is
-- valeur accumulée
constant k : integer := integer(round(2.0 ** real(N) * fClkOut / fClkRef));
-- fréquence de sortie
constant fClkOutVrai : real := fClkRef * real(k) / 2.0 ** N;
-- erreur relative sur la fréquence de sortie, en %
constant erreurRelative : real := 100.0 * abs(fClkOut - fClkOutVrai) / fClkOut;
signal compteur : unsigned(N - 1 downto 0) := (others => '0');
begin
assert erreurRelative < 1.0
report "Avertissement - imprécision de la fréquence de sortie"
& ", fClkOut demandée: " & real'image(fClkOut)
& ", fClkOut obtenue: " & real'image(fClkOutVrai)
& ", erreur relative: " & integer'image(integer(erreurRelative)) & "%"
& ", il faut augmenter la largeur de l'accumulateur."
severity warning;
process (clkRef)
begin
if rising_edge(clkRef) then
compteur <= compteur + k;
end if;
end process;
clkout <= compteur(compteur'left);
end clockgen;
Exemple 8-2 – synthétiseur numérique d’horloge
Dans le cas extrême, le mot de contrôle est fixé à 1 et le circuit se résume à un compteur dont le bit le plus
significatif sert de signal d’horloge. Ce circuit n’est adéquat que lorsqu’on désire diviser la fréquence
d’horloge de référence par une valeur égale à une puissance de 2.
Le désavantage du synthétiseur numérique d’horloge est que, pour les cas où le rapport des fréquences
n’est pas égal à une puissance de 2, l’horloge de sortie souffre de vacillement. La période entre les oscillations varie légèrement, même si en moyenne elle est égale à la période désirée.
INF3500 : Conception et réalisation de systèmes numériques
143
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
8.8
Conception et implémentation pour FPGA
8.8.1
Conception synchrone
On obtient en général de bien meilleurs résultats avec un FPGA en adoptant un style de conception synchrone. Les structures asynchrones sont mal adaptées aux FPGAs.
Il faut aussi éviter de se fier aux délais d’une composante ou du routage d’un signal, surtout si on utilise
un synthétiseur et des outils d’implémentation automatiques. Par exemple, on pourrait être tenté de retarder un signal en le faisant passer par deux inverseurs en cascade. Cependant, un synthétiseur aura tôt fait
d’éliminer cette structure inutile du point de vue fonctionnel.
Les signaux d’initialisation des bascules devraient aussi être synchrones.
8.8.2
Bascules vs loquets
Dans un ASIC sur mesure ou un ASIC à cellules normalisées, les loquets offrent plusieurs avantages.
Tout d’abord, ils requièrent la moitié des transistors d’une bascule. En utilisant des techniques spéciales,
on parvient à obtenir des circuits fiables et plus rapides qu’avec des bascules.
Cependant, pour un FPGA le coût est identique entre une bascule et un loquet. Il est donc grandement
avantageux de toujours utiliser des bascules. Entre autres, cela améliore la qualité de l’analyse statique
des délais ce qui permet de mieux estimer la performance du circuit.
8.8.3
Initialisation globale
Il est avantageux d’utiliser un signal unique pour initialiser toutes les bascules parce que la plupart des
FPGAs comportent un chemin spécial pour accomplir cette tâche.
8.8.4
Génération et distribution de signaux d’horloge
Pour les implémentations sur FPGA, quand on génère un signal d’horloge il est important de prendre en
considération le routage de celui-ci aux différentes bascules du circuit. Comme on l’a vu à la section 8.4,
un routage inadéquat résulte en un déphasage d’horloge qui réduit les performances du circuit.
De façon à éviter cet état de chose, il faut spécifier à l’outil de synthèse qu’un certain signal est un signal
d’horloge. Le synthétiseur peut alors utiliser l’un des tampons spéciaux disponibles sur le FPGA ainsi que
les circuits réservés pour la distribution de l’horloge. Pour les outils de Xilinx, il faut insérer le symbole
« BUFG » à la sortie du générateur d’horloge.
8.8.5
Exploitation de toutes les ressources
Les ressources en place dans les blocs logiques configurables d’un FPGA sont ‘gratuites’. En effet, une
fois une puce choisie pour un système, il ne coûte ‘rien’ d’utiliser toutes les ressources qu’elle contient.
Ce genre de raisonnement n’est pas vrai nécessairement pour les autres technologies, comme pour les
ASICs à cellules normalisées, puisque dans ce cas on part avec une planche vide à laquelle on ajoute les
ressources nécessaires au design. On suppose aussi ici que la consommation de puissance n’est pas une
considération primordiale.
Dans ce cas, il est très avantageux d’utiliser les registres présents dans les blocs logiques en adoptant une
architecture à pipeline. Cette approche peut réduire significativement les délais de propagation sur le
chemin critique et accélérer ainsi le débit de données que le système peut supporter. Le seul inconvénient
est l’augmentation de la latence. Beaucoup d’applications sont insensibles à une latence de plusieurs dizaines de cycles d’horloge de 100 MHz ou plus, ce qui rend les architectures à pipeline très intéressantes.
Un corolaire de ce principe est qu’il est avantageux de placer deux registres supplémentaires dans le chemin de chaque entrée et sortie du système. Pour une entrée, le premier registre est placé dans le bloc
INF3500 : Conception et réalisation de systèmes numériques
144
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
d’entrées-sorties du FPGA, diminuant au minimum le délai pour la saisie du signal. Le deuxième registre
donne beaucoup de flexibilité au placeur et au routeur pour déterminer l’emplacement optimal du module
qui doit traiter ce signal. En effet, comme il n’y a pas de fonction logique entre le premier et le deuxième
registre, la distance physique entre les deux peut être aussi grande que le permet le délai de propagation
par rapport au délai du chemin critique, qui lui comporte une partie due à la fonction logique et une partie
due au routage.
Les délais de propagation peuvent être grandement réduits en limitant la charge à la sortie d’un module.
On peut atteindre ce but en employant un arbre de distribution. Le principe consiste à faire mener une
charge réduite composée d’un groupe de bascules. Chacune de ces bascules peut ensuite mener les modules qui doivent recevoir le signal. Dans la description du circuit, il s’agit d’utiliser des noms différents
pour des signaux identiques, ce qui devrait empêcher l’outil de synthèse de les combiner.
La disponibilité d’un grand nombre de bascules sur un FPGA favorise grandement l’encodage à une bascule par état (one-hot) pour les machines à états.
8.8.6
Gestion manuelle de la disposition
Il peut être très avantageux de faire la gestion manuelle de la disposition (floorplanning) pour les parties
critiques d’un circuit. Les manufacturiers de FPGA offrent des outils qui permettent de déterminer la position absolue ou relative de certains registres sur la puce. On laisse ensuite les outils automatisés faire la
disposition du reste du circuit. En plaçant manuellement les blocs les plus lents, on facilite la tâche du
placeur automatique et on accélère cette étape. L’avantage principal, cependant, est qu’on peut en arriver
à une solution réellement optimale (i.e. qui ne peut être améliorée). L’inconvénient est que ce travail peut
être ardu et pénible, et il devrait donc être réservé uniquement aux parties critiques d’un système.
8.8.7
Arithmétique en virgule flottante ou fixe
La plupart des gens sont habitués à obtenir une très grande précision dans les calculs (8 chiffres significatifs et plus). Les calculatrices nous offrent cette précision, tout comme les microprocesseurs de nos stations de travail. En pratique cependant, on requiert très rarement cette précision.
En effet, à part pour les applications financières et certaines applications scientifiques, de trois à cinq
chiffres significatifs suffisent amplement. Ceci est spécialement vrai pour les systèmes qui traitent des
données provenant de phénomènes naturels comme les sons ou les signaux électromagnétiques. La voix
dans un système téléphonique est échantillonnée avec 8 bits de précision, alors que les sons enregistrés
sur un CD audio le sont avec 16 bits.
Il y a au moins un ordre de grandeur de différence en complexité et en performance entre un circuit
arithmétique qui fonctionne en virgule fixe par rapport à un circuit semblable qui fonctionne en virgule
flottante.
Dans de tels cas, il est utile lors de la modélisation du circuit de tenir compte de ce fait et de mesurer les
conséquences d’utiliser un système à virgule fixe. On peut alors choisir une précision suffisante pour éliminer tout effet indésirable. Par exemple, en représentant les quantités avec 10 bits, on obtient une précision de 3 chiffres significatifs. Avec 20 bits, on obtient 6 chiffres significatifs.
8.9
Documentation de systèmes numériques
La documentation adéquate d’un système numérique est essentielle à toutes les étapes de son cycle de vie.
Dans la phase de conception et de réalisation, la documentation formalise le processus en assurant que les
procédures nécessaires sont suivies. Elle permet de suivre l’évolution du design dans le temps par des
balises définies systématiquement. Pour le travail en équipe, la documentation est absolument essentielle.
INF3500 : Conception et réalisation de systèmes numériques
145
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
Dans la phase de maintenance, la documentation permet de comprendre le fonctionnement du circuit pour
le réparer et le mettre à jour. Ceci est vrai autant pour une personne qui doit modifier un système conçu
par d’autres que pour le cas où l’on doit modifier son propre systèmes plusieurs mois plus tard.
Tous les principes de documentation du logiciel s’appliquent à la documentation d’un système numérique.
Cependant, elle comporte des éléments différents. On peut noter entre autres les éléments suivants.

Les diagrammes de bloc identifient les modules principaux du système ainsi que les interfaces entre
les modules. Dans un diagramme de bloc, on devrait éviter d’identifier des composantes particulières.
Le but de ce diagramme est de donner une vue d’ensemble du système sans nécessairement spécifier
son implémentation. Il peut être utile de spécifier les noms des signaux d’interface de haut niveau.

Une description fonctionnelle du système sous forme de texte narratif permet d’expliquer comment
celui-ci doit se comporter dans différentes situations. C’est aussi dans ce genre de document qu’on
peut expliquer les particularités du système, la philosophie du design, et les raisons qui ont poussé les
concepteurs à choisir certaines options plutôt que d’autres.

Une description des fonctions logiques du système peut être formée d’une combinaison de schémas
logiques, de code HDL et de diagrammes d’états. Pour le travail en équipe, le code HDL doit suivre
des directives et conventions acceptées par le groupe. Ces conventions devraient inclure des paramètres aussi diversifiés qu’un format normalisé pour les en-têtes de fichiers, la façon de choisir des
identificateurs et la façon d’écrire une structure de sélection. Des conventions doivent aussi être en
place pour les schémas logiques et les diagrammes d’états. Il faut éviter que les schémas logiques ressemblent à des spaghettis en limitant le nombre de modules sur un seul schéma en les hiérarchisant.
On augmente grandement la lisibilité d’un diagramme en réduisant la longueur des interconnexions et
en réduisant le nombre d’angles dans les interconnexions.

Des diagrammes de synchronisation décrivent les caractéristiques dynamiques du système. On spécifie habituellement trois paramètres : une valeur maximale, une valeur minimale, et une valeur typique. La valeur typique est celle qu’on peut s’attendre d’observer dans la plupart des cas. Les valeurs
minimale et maximale doivent être utilisées pour concevoir un système robuste en toute situation.

Les schémas électriques énumèrent les composantes matérielles du système et identifient les connexions de patte à patte. À partir du schéma, on doit pouvoir dresser la liste des matériaux nécessaires
pour construire le circuit (bill of materials – BOM). En fait, il devrait être possible de construire le
circuit sans en comprendre le fonctionnement.
8.10
Quelques principes importants en conception numérique
Ces excellentes recommandations sont inspirées en partie du livre de Wakerly.

De bons outils de conception et d’analyse ne garantissent pas le succès mais facilitent la tâche.

Les circuits numériques sont bâtis avec des composantes analogiques et ont donc des caractéristiques
analogiques dont il faut tenir compte.

Documenter, documenter, documenter. Pour les autres, mais surtout pour vous.

Utiliser des pratiques normalisées de codage et de documentation sauve beaucoup de temps.

La conception de machines à états est un art similaire à celui de la programmation.

Toujours rechercher la manière la plus efficace d’atteindre le but.

Le système qui doit être conçu devra éventuellement être fabriqué et testé. On gagne beaucoup à tenir
compte de la testabilité du système pendant sa conception.

La logique programmable est d’une grande utilité à cause de la flexibilité qu’elle offre au concepteur.
INF3500 : Conception et réalisation de systèmes numériques
146
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques

Éviter les systèmes asynchrones.

Porter une attention particulière à la synchronisation entre deux systèmes synchrones ou non mais
asynchrones l’un par rapport à l’autre.

Le débogage d’un système est un art qui repose sur la maîtrise des trois principes suivants :
8.11

la compréhension de la spécification;

le contrôle des entrées du module à déboguer; et,

l’observation des signaux internes, de l’état et des sorties du module à déboguer.
Exercices
1. Pour le circuit suivant, identifiez le chemin critique et déterminez la fréquence maximale d’horloge.
Donnez la marge libre de préparation pour les autres chemins. Supposez que les bascules ont un
temps de préparation de 1 ns et un délai de propagation de 2 ns et qu’on peut négliger les délais des
interconnexions. Supposez qu’il n’y a pas de déphasage d’horloge.
D Q
D Q
A
CLK
3 ns
D
3 ns
CLK
2 ns
3 ns
D Q
B
1 ns
D Q
2 ns
CLK
E
CLK
D Q
C
2 ns
4 ns
CLK
2 ns
2. Considérez le circuit suivant. Les bascules ont des délais de propagation de 2 ns, un temps de préparation de 1 ns, et un temps de maintien de 1 ns. Il y a trois chemins à considérer : des bascules 1/2 à la
bascule 3, de la bascule 2 à la bascule 4, et des bascules 3/4 à la bascule 1. Pour chaque chemin, déterminer les valeurs acceptables de déphasage d’horloge. Supposez que la période d’horloge est égale
à 10 ns.
INF3500 : Conception et réalisation de systèmes numériques
147
v. 2.5, juillet 2013
Chapitre 8 : Considérations pratiques
D Q
D Q
1
CLK
3 ns
3
CLK
D Q
D Q
2
4
CLK
CLK
CLK
2 ns
délai
3. Donnez le code VHDL pour un double tampon tel que montré à la Figure 8-4. Ce circuit peut vous
être utile dans vos laboratoires.
4. Donnez le code VHDL correspondant au circuit de la Figure 8-5, puis modifiez-le pour correspondre
au circuit de la Figure 8-6.
5. Donnez une équation exprimant le potentiel de réduction de la fréquence minimale d’horloge à l’aide
d’une architecture à pipeline, en fonction des différents délais du circuit.
6. Inspectez le rapport de synthèse d’un des circuits de vos laboratoires afin d’obtenir les délais des différentes composantes sur le chemin critique. Pouvez-vous retracer le chemin critique dans votre code
VHDL à l’aide du rapport?
7. Simulez le circuit de l’Exemple 8-2 et observez son comportement quand vous variez les différents
paramètres. Commentez la ligne avec l’énoncé assert afin d’observer ce qui se passe quand les
contraintes ne sont pas respectées. Mesurez la fréquence d’entrée et de sortie.
8. Expliquez les différences entre les concepts de latence et de débit. Expliquez pourquoi en pratique ces
deux concepts ne peuvent être optimisés indépendamment.
9. Expliquez ce qu’est le partage des ressources.
10. On vous propose d’ajouter des états à une unité de contrôle d’un processeur pour réduire la complexité de son chemin des données. Est-ce une approche valide? Dans quelle(s) circonstance(s)?
INF3500 : Conception et réalisation de systèmes numériques
148
v. 2.5, juillet 2013
Chapitre 9
Conception et réalisation de processeurs à usage général
9.1
Introduction
9.1.1
Description
Un processeur à usage général se distingue d’un processeur à usage spécifique par le fait qu’il peut être
programmé. Le programme est une suite d’instructions codées numériquement et gardées en mémoire.
Certains processeurs à usage général, comme les processeurs Pentium de Intel et les processeurs Sparc de
Sun, sont destinés principalement au marché des stations de travail. Ce sont des circuits d’une complexité
inouïe qui sont le résultat du travail de centaines d’ingénieurs-années. D’autres processeurs, comme les
ARM, MIPS, 8051 et TMS320 sont peu connus mais sont fréquemment utilisés dans des applications
embarquées comme les téléphones cellulaires, les automobiles et les jeux vidéo.
Les processeurs à usage général sont habituellement fabriqués à très, très grande échelle. Leurs coûts de
développement faramineux peuvent donc être répartis sur un très grand nombre d’unités, rendant rentable
leur production et mise en marché.
Il est intéressant d’observer que le développement de chaque nouvelle génération de processeur se fait à
l’aide de stations de travail équipées de processeurs de la génération précédente. En d’autres mots, sans la
puissance de calcul des processeurs d’aujourd’hui, on serait incapable de concevoir les processeurs de
demain.
9.1.2
Jeu d’instructions
Le jeu d’instructions (Instruction Set Architecture – ISA) est la spécification de toutes les instructions
pouvant être effectuées par le processeur, leur encodage numérique, et l’inventaire des ressources mises à
la disponibilité des programmeurs (comme des registres, des piles, des coprocesseurs, etc.). Le jeu
d’instructions est le contrat entre les concepteurs du processeur et les programmeurs.
On peut catégoriser les jeux d’instructions selon plusieurs dimensions. Le but de la présente discussion
n’est pas de les couvrir toutes. Une dimension concerne la forme du chemin des données du processeur,
selon qu’il contient ou non des registres et de la mémoire. On va donc considérer, pour la suite de la discussion, des processeurs de type registre-registre (register-register ou load-store). Pour ce type de processeur, les opérations peuvent être effectuées uniquement sur des valeurs gardées dans des registres. Il est
possible de transférer des données entre les registres et la mémoire.
On va aussi considérer des processeurs basés sur l’architecture Harvard, c'est-à-dire qui ont des mémoires
séparées pour le programme et les données (contrairement à l’architecture Von Neumann).
Pour plus de détails sur les jeux d’instructions et la classification des processeurs, on peut consulter tout
bon livre d’architecture des ordinateurs, comme le classique de Hennessy et Patterson.
9.1.3
Micro-opérations du chemin des données
Contrairement à un processeur à usage spécifique, la grande taille du jeu d’instructions d’un processeur à
usage général implique qu’il faut pouvoir supporter un grand nombre de micro-opérations. On peut toutefois les classifier en trois groupes :

le chargement de données de l’extérieur ou une mémoire vers un bloc de registres;

la transformation des données grâce à une unité arithmétique et logique; et,

l’entreposage de données en mémoire ou leur transfert vers l’extérieur.
INF3500 : Conception et réalisation de systèmes numériques
149
v. 2.42, décembre 2009
Chapitre 9 : Conception et réalisation de processeurs à usage général
9.1.4
Notes sur l’architecture
Un processeur à usage général reste basé sur l’architecture présentée à la Figure 5-1 et répétée ici à la
Figure 9-1, c'est-à-dire qu’il peut être décomposé en un chemin des données et une unité de contrôle.
Sortie des données
Entrée des données
Chemin des données
État
Contrôle
Entrées de contrôle
Sorties de contrôle
Unité de contrôle
Figure 9-1 – architecture d’un processeur à usage général
9.2
Chemin des données d’un processeur à usage général
9.2.1
Architecture générale
Le chemin des données d’un processeur à usage général est montré à la Figure 9-2. Les parties principales
sont le bloc des registres (register file), l’unité arithmétique et logique (UAL) et la mémoire des données.
Le chemin des données reçoit un certain nombre de signaux de contrôle en plus d’une horloge et d’un
signal de réinitialisation. La plupart des signaux de contrôle sont dirigés vers l’un des trois blocs principaux. L’exception est le signal choixSource qui contrôle un multiplexeur permettant de choisir l’une
de quatre sources pour le bloc des registres. Le signal constante provient de l’unité de contrôle et le
signal entréeExterne provient d’un bloc d’entrées-sorties du processeur. Le signal
sortieExterne permet quant à lui de transmettre des valeurs à un bloc d’entrées-sorties.
choixSource
constante
entréeExterne
0
1
2
3
registre d’état
état
donnée
A
sortie
adresse
bloc des registres
clk
B
F
B
charge
clk
lecture/ecriture’
UAL
choixCharge
mémoire des données
A
choixA
choixB
opération
entree
sortieExterne
Figure 9-2 – chemin des données d’un processeur à usage général
INF3500 : Conception et réalisation de systèmes numériques
150
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
9.2.2
Le bloc des registres
Le bloc des registres manipule la plupart des données du processeur. Il contient un certain nombre de
registres de largeurs identiques. Le nombre de registres peut varier de 1 seul à 1024, et leur largeur peut
varier de 4 à 128 bits. En général, quant on parle d’un processeur à 32 ou 64 bits, on spécifie la largeur
des registres de son bloc des registres.
Le bloc des registres a en général deux sorties vers l’UAL, qui sont les opérandes sur lesquelles les calculs sont effectués. Deux signaux de contrôle, choixA et choixB, permettent de choisir quel registre
est dirigé à chacune des sorties.
Le bloc des registres contient une entrée à charger dans un des registres. Le signal charge indique que
la valeur doit être chargée, et le signal choixCharge spécifie dans quel registre.
Le modèle de bloc de registres décrit ici a donc un port d’entrée et deux ports de sortie. Il est possible
d’augmenter le nombre de ces ports selon les besoins.
9.2.3
Organisation du bloc de registres : transfert par multiplexeurs
La Figure 9-3 illustre un bloc de quatre registres dont les sorties sont contrôlées par multiplexeurs. Deux
multiplexeurs reçoivent en entrée la sortie de chacun des registres, et les signaux de contrôle choixA et
choixB permettent de choisir quel registre est dirigé à chacune des sorties.
D
donnée
Q
R0
charge
charge
choixA
D
Q
A
2:4
choixCharge
R1
charge
0
1
2
3
D
Q
R2
charge
choixB
B
D
Q
R3
charge
Figure 9-3 – bloc des registres avec multiplexeurs
Pour charger les registres, un décodeur reçoit un signal de deux bits, choixCharge, et active l’une de
quatre sorties. Chacun de ces signaux est combiné avec le signal charge dans une porte ET avant d’être
connecté au port de chargement de chacun des registres. Les entrées des registres sont toutes reliées au
signal d’entrée donnée.
La Figure 9-3, n’inclut ni les signaux d’horloge ni les signaux de réinitialisation des registres.
INF3500 : Conception et réalisation de systèmes numériques
151
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
Le désavantage de cet arrangement est le grand nombre de connexions requises aux multiplexeurs de
sortie. Dans la Figure 9-3, on a fait abstraction de la largeur des registres. Pour un bloc avec des registres
de 64 bits, il faut alors avoir 128 multiplexeurs pour contrôler chacun des bus de sortie A et B. Plus que
les multiplexeurs, c’est le routage des fils à la sortie des registres qui est problématique et qui risque de
ralentir le circuit.
9.2.4
Organisation du bloc de registres : transfert par bus
Une organisation plus efficace du point de vue du routage des signaux de sortie est montrée à la Figure
9-4. Ici, on utilise des bus avec des tampons à trois états. Les tampons à trois états sont décrits à la section
5.3.4. À chaque registre est associé un tampon qui mène un bus. Un signal de contrôle permet de connecter ou non la sortie du tampon au bus. Les signaux de contrôle (R0A, R1A, etc.) sont générés à l’aide de
deux décodeurs 2:4 menés par les signaux choixA et choixB.
Le mécanisme de chargement est identique à celui de la Figure 9-3.
R0A
D
donnée
Q
R0B
R0
charge
charge
A
B
R1A
D
Q
R1B
2:4
2:4
choixCharge
R1
charge
0
1
2
3
choixA
0
1
2
3
R0A
R1A
R2A
R3A
R2A
D
Q
R2B
2:4
R2
charge
choixB
R3A
D
Q
0
1
2
3
R0B
R1B
R2B
R3B
R3B
R3
charge
Figure 9-4 – bloc des registres avec bus et tampons à trois états
9.2.5
Modélisation VHDL du bloc des registres
L’Exemple 9-1 illustre la description du bloc des registres en VHDL. Les registres sont représentés à
l’aide d’un tableau d’objets de type signed. Un processus définit le comportement du bloc des registres
comme des bascules activées sur une transition positive du signal d’horloge. Les deux bus de sortie du
bloc des registres sont décrits par des énoncés concurrents à l’extérieur du processus.
On note que rien dans le code VHDL ne spécifie si des multiplexeurs ou des tampons à trois états sont
utilisés. Pour spécifier ce comportement dans le code, il faudrait utiliser une description structurale (voir
la section 2.3.2). Certains synthétiseurs permettent aussi de forcer le style d’implémentation des multiplexeurs. D’autres sont suffisamment sophistiqués pour choisir le style le plus efficace selon la technologie ciblée.
INF3500 : Conception et réalisation de systèmes numériques
152
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
-- dans la partie déclarative de l’architecture
type lesRegistres_type is array(0 to Nreg - 1) of signed(Wd - 1 downto 0);
signal lesRegistres : lesRegistres_type;
signal A : signed(Wd - 1 downto 0);
signal choixA : integer range 0 to Nreg - 1;
signal B : signed(Wd - 1 downto 0);
signal choixB : integer range 0 to Nreg - 1;
signal donnee : signed(Wd - 1 downto 0);
signal choixCharge : integer range 0 to Nreg - 1;
signal charge : std_logic;
-- dans le corps de l’architecture
process (CLK, reset)
begin
if rising_edge(CLK) then
if reset = '1' then
lesRegistres <= (others => (others => '0'));
else
if charge = '1' then
lesRegistres(choixCharge) <= donnee;
end if;
end if;
end if;
end process;
-- signaux de sortie du bloc des registres
A <= lesRegistres(choixA);
B <= lesRegistres(choixB);
sortieExterne <= B;
Exemple 9-1 – bloc des registres
La réinitialisation du bloc des registres est décrite avec l’expression (others=>(others=>'0'))
qui imbrique deux clauses others. Cela est nécessaire parce que le bloc des registres est une structure
de données à deux dimensions.
Le code de l’Exemple 9-1 exploite le type integer pour spécifier les registres à charger et de sortie.
Cela clarifie grandement le code. Il est important cependant de spécifier les gammes de valeurs attendues,
sinon le synthétiseur risquerait de produire un circuit beaucoup plus complexe que nécessaire afin de
pouvoir accommoder toutes les valeurs possibles correspondant à ce type.
Le code de l’Exemple 9-1 exploite aussi l’utilisation de paramètres pouvant être déclarés avec des énoncés generic. Ces paramètres sont Nreg pour le nombre de registres et Wd pour la largeur du chemin
des données en bits.
9.2.6
Unité arithmétique et logique
L’unité arithmétique et logique a été décrite par parties aux sections 5.5 et 5.5.1. Un exemple de code
VHDL pour une UAL simple à 8 opérations est donné à l’Exemple 9-2.
La complexité de l’UAL dépend directement du nombre d’opérations qu’elle doit pouvoir supporter. Elle
dépend bien sûr aussi de la largeur des opérandes. En pratique, la largeur de l’UAL est identique à celle
du bloc des registres. Il existe certains cas particuliers où l’UAL est plus large, comme dans les processeurs dédiés au traitement numérique du signal. Pour ces processeurs, l’UAL conserve parfois les résultats
avec une plus grande précision quand ces résultats doivent être réutilisés pour plusieurs calculs consécutifs avant un arrondi final.
INF3500 : Conception et réalisation de systèmes numériques
153
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
-- dans la partie déclarative de l’architecture
signal
signal
signal
signal
F : signed(Wd - 1 downto 0);
Z : std_logic;
N : std_logic;
op : integer range 0 to 7;
-- dans le corps de l’architecture
process(A, B, op)
begin
case op is
when 0 => F
when 1 => F
when 2 => F
when 3 => F
when 4 => F
when 5 => F
when 6 => F
when 7 => F
when others
end case;
end process;
<=
<=
<=
<=
<=
<=
<=
<=
=>
A + B;
A - B;
shift_right(A, 1);
shift_left(A, 1);
not(A);
A and B;
A or B;
A;
F <= (others => 'X');
-- registre d'état de l'UAL
process(clk, reset)
begin
if rising_edge(clk) then
if reset = '1' then
Z <= '0';
N <= '0';
else
if (etat = opUAL) then
if F = 0 then Z <= '1'; else Z <= '0'; end if;
N <= F(F'left);
end if;
end if;
end if;
end process;
Exemple 9-2 – unité arithmétique et logique
Plusieurs auteurs distinguent l’UAL et le module de décalage. Nous choisissons ici de les joindre, c'est-àdire que l’UAL est capable d’effectuer des opérations arithmétiques, logiques et de décalage.
Conformément à la Figure 9-2, l’UAL de l’Exemple 9-2 inclut un registre d’état. La fonction de ce registre est d’entreposer un mot d’information sur la dernière opération effectuée, comme un résultat négatif
ou nul, un débordement ou la génération d’une retenue. Ici l’état se résume à 2 bits, Z et N, indiquant
respectivement un résultat nul ou négatif. Lors d’une opération sur l’UAL, le résultat est entreposé dans
un registre du bloc des registres. L’état correspondant est entreposé dans le registre d’état. Cette approche
simplifie la synchronisation avec l’unité de contrôle.
9.2.7
Mémoire des données
En théorie, un processeur avec un bloc des registres suffisamment grand n’aurait pas besoin d’une mémoire des données associée. C’est souvent le cas pour les processeurs spécialisés. En pratique cependant,
un processeur à usage général a toujours besoin d’une telle mémoire. Pour la mémoire des données, on
doit utiliser une mémoire vive (Random Access Memory – RAM), dans laquelle les données peuvent être
lues, écrites ou effacées.
INF3500 : Conception et réalisation de systèmes numériques
154
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
Pour la plupart des processeurs, la mémoire des données est placée à l’extérieur de celui-ci. Dans le cas
présent on simplifie les choses en intégrant la mémoire au processeur.
La mémoire des données a en général un port de sortie, un port d’entrée, un port d’adresse et un port de
contrôle de l’opération. À l’image du bloc des registres, la mémoire peut avoir plusieurs ports d’entrée et
de sortie. En général, il est utile que les cellules de la mémoire aient la même taille que celles du bloc des
registres, mais ce n’est pas strictement nécessaire.
Le port d’adresse spécifie une cellule de la mémoire en particulier. Le signal lecture/ecriture’
détermine si la cellule sera lue (1) ou écrite (0).
La Figure 9-2 montre comment la mémoire est reliée au reste du chemin des données. La sortie de la mémoire peut être dirigée vers le port d’entrée du bloc des registres via un multiplexeur. L’entrée de la mémoire est quant à elle reliée à une des deux sorties du bloc des registres.
La description d’une mémoire des données en VHDL peut prendre plusieurs formes, selon une multitude
de paramètres. Ceux-ci incluent, entre autres :

le nombre de ports d’entrée et de sortie;

le fait que les sorties soient synchrones ou asynchrones;

le nombre de cycles nécessaires à la mémoire pour déplacer des données;

la présence de signaux d’activation; et,

la spécification de valeurs initiales.
Du code VHDL pour une mémoire des données est montré à l’Exemple 9-3. Pour simplifier les choses, la
description est virtuellement identique à celle du bloc des registres de l’Exemple 9-1. En pratique, la lecture d’une donnée en mémoire nécessite un cycle d’horloge pour charger l’adresse à lire. Le contenu de la
cellule de mémoire correspondante n’est disponible qu’au cycle suivant, ou, dans le cas de certaines mémoires, plusieurs cycles plus tard.
-- dans la partie déclarative de l’architecture
type memoireDonnees_type is array(0 to 2 ** Md - 1) of signed(Wd - 1 downto 0);
signal memoireDonnees : memoireDonnees_type;
signal sortieMemoireDonnees : signed(Wd - 1 downto 0);
signal adresseMemoireDonnees : integer range 0 to 2 ** Md - 1;
signal lectureEcritureN : std_logic;
-- dans le corps de l’architecture
-- mémoire des données
process (CLK)
begin
if rising_edge(CLK) then
if lectureEcritureN = '0' then
memoireDonnees(adresseMemoireDonnees) <= B;
end if;
end if;
end process;
sortieMemoireDonnees <= memoireDonnees(adresseMemoireDonnees);
Exemple 9-3 – mémoire des données
Il est important de vérifier la documentation du synthétiseur utilisé pour obtenir le type de mémoire désiré
selon la technologie ciblée. La description de l’Exemple 9-3 est inspirée du manuel de l’utilisateur du
synthétiseur XST de Xilinx pour utiliser de la mémoire distribuée sur les blocs de logique programmable
INF3500 : Conception et réalisation de systèmes numériques
155
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
de la puce. La version 2007 du manuel spécifie 16 façons différentes de décrire des blocs de mémoire
vive, et chacune ne mène pas nécessairement à la même utilisation des ressources de la puce.
Le code utilise deux paramètres définis par des énoncés generic. Le premier, Md, spécifie le nombre de
bits d’adresse de la mémoire. Le nombre de cellules correspondant peut facilement être calculé à partir du
nombre de bits d’adresse. Le deuxième, Wd, donne la largeur des cellules de mémoire en bits. En pratique,
cette largeur devrait correspondre à celle du bloc des registres et de l’UAL.
9.2.8
Multiplexeur du signal d’entrée du bloc des registres
La Figure 9-2 montre un multiplexeur qui détermine lequel de quatre signaux est acheminé à l’entrée du
bloc des registres. Ces quatre signaux sont : la sortie de l’UAL, une constante qui proviendrait de l’unité
de contrôle, une entrée externe au processeur venant d’un bloc d’entrées-sorties, et la sortie de la mémoire
des données. L’Exemple 9-4 donne le code VHDL pour ce multiplexeur.
-- dans la partie déclarative de l’architecture
-- signaux du multiplexeur contrôlant la source du bloc des registres
signal constante : signed(Wd - 1 downto 0);
signal choixSource : integer range 0 to 3;
-- dans le corps de l’architecture
process (F, constante, entreeExterne, sortieMemoireDonnees, choixSource)
begin
case choixSource is
when 0 => donnee <= F;
when 1 => donnee <= constante;
when 2 => donnee <= entreeExterne;
when 3 => donnee <= sortieMemoireDonnees;
when others => donnee <= F;
end case;
end process;
Exemple 9-4 – multiplexeur
Le multiplexeur est modélisé par un énoncé case à l’intérieur d’un processus. Le signal choixSource
est le signal de contrôle qui permet de choisir parmi l’une de quatre sources.
9.2.9
Signaux de contrôle et instructions sur le chemin des données
Pour effectuer une instruction avec le chemin des données proposé, il s’agit de donner les bonnes valeurs
aux différents signaux de contrôle.
Supposons par exemple que le bloc des registres contient seize registres R0, R1, … R15 et que la mémoire contient 256 cellules. Le Tableau 9-1 donne quelques exemples d’instructions, encodées sous la
forme de micro-opérations, avec les signaux de contrôle correspondants. Le tiret ‘-‘ indique que la valeur
est sans importance (don’t care).
Par exemple, pour copier le contenu du registre R1 dans le registre R0, il faut aiguiller la valeur du registre R1 à l’extérieur du bloc des registres, à travers l’UAL (qui n’effectue aucune opération), puis à
travers du multiplexeur de sélection de source, pour revenir à l’entrée du bloc des registres. Le signal sur
le port B du bloc des registres n’est pas utilisé et est sans importance. La mémoire ne doit pas charger de
nouvelle valeur pendant cette opération.
Le Tableau 9-1 inclut deux instructions de manipulation des données avec la mémoire. Pour ces instructions, un M majuscule est utilisé avec un nombre entre crochets. Le nombre indique l’adresse de la cellule
de mémoire considérée.
INF3500 : Conception et réalisation de systèmes numériques
156
v. 2.5, juillet 2013
choixSource
choixCharge
charge
choixA
choixB
opération
lectureEcriture’
Chapitre 9 : Conception et réalisation de processeurs à usage général
R0 ← R1
0
0
1
1
-
7
1
R2 ← R1 + R3
0
2
1
1
3
0
1
R2 ← R2 ET R3
0
2
1
2
3
5
1
R3 ← M[25]
3
3
1
-
-
-
1
M[25] ← R0
-
-
0
-
0
-
0
instruction
Tableau 9-1 – signaux de contrôle et exemples d’instructions
L’architecture décrite à la Figure 9-2 ne permet pas d’effectuer deux opérations simultanément. Par
exemple, pour copier le contenu de deux cellules de mémoire dans deux registres, il faut effectuer deux
opérations. Pour additionner le contenu de deux cellules de mémoire et entreposer la somme dans une
autre cellule, il faut quatre opérations : une pour copier le premier opérande, une pour copier le deuxième
opérande, une pour calculer la somme et la sauvegarder dans un registre, et une dernière pour copier la
somme dans une cellule de mémoire.
L’unité de contrôle
9.3
L’unité de contrôle du processeur doit effectuer les opérations en fonction des instructions du programme
à exécuter.
9.3.1
Architecture générale
L’unité de contrôle est composée des blocs suivants :

une mémoire des instructions contenant le programme à exécuter;

un compteur de programme (Program Counter – PC) qui pointe à la prochaine instruction à exécuter;

un registre d’instruction (Instruction Register – IR) qui contient l’instruction courante; et,

un contrôleur qui implémente une machine à états et qui génère les signaux de contrôle pour le chemin des données.
Certains auteurs séparent la mémoire du programme et l’unité de contrôle, mais nous avons choisi de les
combiner ici. On peut aussi considérer le registre d’états de l’UAL comme faisant partie de l’unité de
contrôle. L’unité de contrôle est montrée à la Figure 9-5.
9.3.2
Cycle des instructions et machine à états
Pour exécuter une instruction, l’unité de contrôle doit exécuter la séquence de tâches suivante :

Aller quérir l’instruction à exécuter (fetch). Dans cette étape, le registre des instructions est chargé
avec le contenu de la cellule de la mémoire des instructions pointée par le compteur de programme.
Le compteur de programme est ensuite incrémenté pour pointer à la prochaine instruction ou à des
données emmagasinées immédiatement après l’instruction en cours.
INF3500 : Conception et réalisation de systèmes numériques
157
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général

Décoder l’instruction (decode). Dans cette étape, le contrôleur doit décoder l’instruction obtenue afin
de générer les signaux de contrôle pour le chemin des données.

Exécuter l’instruction (execute). Dans cette étape, le chemin des données exécute l’instruction. Cette
étape peut être décomposée en plusieurs états selon la complexité de l’instruction.
La machine à états montrée à la Figure 9-6 illustre ces étapes.
registre
d’instruction
Q
charge
mémoire des instructions
contrôleur
compteur de
programme
Q
adresse
D
signaux de controle
D
sortie
etatUAL
compte
charge
Figure 9-5 – unité de contrôle d’un processeur à usage général
reset
depart
quérir
IR <= MI[PC]
PC <= PC + 1
décoder
exécuter
Figure 9-6 – cycle des instructions de base
INF3500 : Conception et réalisation de systèmes numériques
158
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
9.3.3
Encodage des instructions en mémoire
On pourrait emmagasiner une instruction en mémoire directement en entreposant tous les signaux de contrôle correspondant à cette instruction. Cependant, il est plus efficace de les encoder afin de réduire la
taille du programme. De plus, le jeu des instructions est une spécification fixe pour un processeur, mais
un processeur peut avoir plusieurs implémentations différentes. On préfère donc découpler le jeu
d’instructions des signaux de contrôle particuliers du processeur. C’est la tâche du contrôleur de l’unité de
contrôle de décoder les instructions et de générer les bons signaux de contrôle.
Pour le processeur considéré ici, on va faire les suppositions suivantes :

le chemin des données contient 16 registres, de R0 à R15, et chaque registre a 16 bits de large;

l’ALU peut exécuter 8 instructions différentes, énumérées à l’Exemple 9-2; et,

les mémoires des données et des instructions contiennent chacune 256 mots de 16 bits.
Dans le Tableau 9-2, on présente cinq types d’instructions ainsi que leur encodage.
instruction
bits 15-12
bits 11-8
bits 7-4
bits 3-0
{0|op2|op1|op0}
destination
source1
source2
Rdest ← MD[adresse]
1000
destination
adresse[7:4]
adresse[3:0]
MD[adresse] ← Rsource
1001
source
adresse[7:4]
adresse[3:0]
JUMP adresse
1100
condition
adresse[7:4]
adresse[3:0]
STOP
1111
-
-
-
Rdest ← Rsource1 ◊ Rsource2
Tableau 9-2 – encodage d’instructions
Pour l’instruction qui nécessite un traitement par l’ALU, les 3 bits {op2|op1|op0} correspondent à
l’encodage des opérations de l’ALU.
Pour l’instruction JUMP, les différentes combinaisons des bits 11-8 de l’instruction permettent d’avoir
jusqu’à 16 conditions différentes. Le Tableau 9-3 en propose cinq.
condition
bits 11-8 de
l’instruction
aucune
0000
zéro
0001
JNZ
pas zéro
0010
JNeg
négatif
0011
JPos
positif
0100
instruction
JUMP
JZ
Tableau 9-3 – conditions de branchement
Le Tableau 9-4 présente quelques exemples d’encodage d’instructions.
On observe que plusieurs codes ne sont pas valides, comme par exemple ceux qui commencent par 101.
De plus, certaines opérations n’utilisent pas tous les champs. Bien que cela signifie que plus de bits sont
utilisés que nécessaire, cela donne de la flexibilité pour ajouter des instructions au processeur.
INF3500 : Conception et réalisation de systèmes numériques
159
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
instruction
bits 15-12
bits 11-8
bits 7-4
bits 3-0
R7 ← R5 + R2
0000
0111
0101
0010
R9 ← R0 – R11
0001
1001
0000
1011
R8 ← R4
0111
1000
0100
----
R12 ← MD[240]
1000
1100
1111
0000
MD[28] ← R10
1001
1010
0001
1100
JZ 2
1100
0001
0000
0010
Tableau 9-4 – exemples d’instructions
9.3.4
Mémoire des instructions
Contrairement à la mémoire des données, il n’est pas nécessaire pour le processeur de pouvoir écrire dans
la mémoire des instructions. Il est certain que la mémoire doit pouvoir être chargée éventuellement, mais
on suppose ici que ce chargement est effectué lors de la configuration du dispositif sur lequel on implémente le processeur.
La description en VHDL de la mémoire des instructions, présentée à l’Exemple 9-5, est donc grandement
simplifiée par rapport à celle de la description de la mémoire des données présentée à l’Exemple 9-3.
Cette fois, la mémoire est définie dans la partie déclarative de l’architecture comme un tableau constant à
deux dimensions dans lequel on place les valeurs des instructions du programme. Le code de l’Exemple
9-5 définit une mémoire qui contiendrait les 6 instructions données en exemple au Tableau 9-4 suivies de
250 cases contenant FFFF, correspondant à l’instruction STOP. On remarque qu’en VHDL on peut écrire
un littéral en base 16 à l’aide d’un x suivi de chiffres hexadécimaux entre guillemets. On peut aussi donner une valeur par défaut à tous les éléments d’un tableau qu’on n’a pas explicitement spécifié grâce au
mot clé others.
-- dans la partie déclarative de l’architecture
type memoireInstructions_type is array (0 to 2 ** Mi - 1)
of std_logic_vector(Wi - 1 downto 0);
constant memoireInstructions : memoireInstructions_type :=
(x"0752", x"190b", x"7840", x"8cf0", x"9a1c", x"c102", others => x"FFFF");
Exemple 9-5 – mémoire des instructions
9.3.5
Machine à états plus détaillée
La Figure 9-7 illustre une machine à états plus détaillée qui correspond aux instructions du Tableau 9-2.
Elle est similaire à la machine présentée à la Figure 9-6, mais l’état exécuter a été remplacé par
d’autres états. À partir de l’état décoder, la machine peut passer à l’un de cinq états, correspondant aux
cinq types d’instructions décrites dans le Tableau 9-2. Dans chacun des ces états, les signaux de contrôle
appropriés doivent être générés pour le chemin des données.
INF3500 : Conception et réalisation de systèmes numériques
160
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
reset
depart
quérir
IR <= MI[PC]
PC <= PC + 1
décoder
type = stop
STOP
type = déplacement vers la mémoire
type = chargement de la mémoire
type = JUMP
type = UAL
écrire dans
la mémoire
UAL
registreregistre
lire la
mémoire
JUMP
Figure 9-7 – cycle des instructions détaillé
9.3.6
Code VHDL pour l’unité de contrôle
Le code VHDL pour la machine à états de l’unité de contrôle est présenté à l’Exemple 9-6, et l’Exemple
9-7 présente le code VHDL pour les signaux de contrôle.
Le code correspond au diagramme de blocs de la Figure 9-5. L’unité de contrôle a un compteur de programme et un registre d’instructions. Le contrôleur implémente la machine à états de la Figure 9-7 avec
une variable, etat, qui peut prendre l’une de huit valeurs. Dans l’état querir, on charge le registre
d’instruction et on incrémente le compteur de programme. L’état decoder sert uniquement à choisir le
prochain état. Dans l’état jump, on vérifie la condition imposée dans l’instruction (voir le Tableau 9-3) et
la valeur des bits d’état de l’UAL. Si la condition est remplie, alors le compteur de programme est chargé
par l’adresse indiquée dans l’instruction, ce qui correspond à effectuer un branchement dans l’exécution
du programme. Pour toutes les instructions sauf stop, la machine retourne ensuite à l’état querir et le
cycle recommence.
INF3500 : Conception et réalisation de systèmes numériques
161
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
-- dans la partie déclarative de l’architecture
type type_etat is (depart, querir, decoder, stop, ecrireMemoire, lireMemoire, opUAL,
jump);
signal etat : type_etat;
signal PC : integer range 0 to (2 ** Mi - 1); -- compteur de programme
signal IR : std_logic_vector(Wi - 1 downto 0); -- registre d'instruction
-- dans le corps de l’architecture
process (CLK, reset)
begin
if rising_edge(CLK) then
if reset = '1' then
etat <= depart;
else
case etat is
when depart =>
PC <= 0;
etat <= querir;
when querir =>
IR <= memoireInstructions(PC);
PC <= PC + 1;
etat <= decoder;
when decoder =>
if (IR(15) = '0') then
etat <= opUAL;
else
case IR(14 downto 12) is
when "000" => etat <= lireMemoire;
when "001" => etat <= ecrireMemoire;
when "100" => etat <= jump;
when "111" => etat <= stop;
when others => etat <= stop;
end case;
end if;
when opUAL | lireMemoire | ecrireMemoire =>
etat <= querir;
when jump =>
if
(IR(11 downto 8) = "0000") or -- branchement
(IR(11 downto 8) = "0001" and Z = '1') or -(IR(11 downto 8) = "0010" and Z = '0') or -(IR(11 downto 8) = "0011" and N = '1') or -(IR(11 downto 8) = "0100" and N = '0') -- si
then
PC <= to_integer(unsigned(IR(7 downto 0)));
end if;
etat <= querir;
when stop =>
etat <= stop;
when others =>
etat <= depart;
end case;
end if;
end if;
end process;
sans condition
si = 0
si /= 0
si < 0
>= 0
Exemple 9-6 – unité de contrôle du processeur général – machine à états
INF3500 : Conception et réalisation de systèmes numériques
162
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
adresseMemoireDonnees <= to_integer(unsigned(IR(7 downto 0)));
lectureEcritureN <= '0' when etat = ecrireMemoire else '1';
choixSource <= 0 when etat = opUAL else 3;
choixCharge <= to_integer(unsigned(IR(11 downto 8)));
choixA <= to_integer(unsigned(IR(7 downto 4)));
choixB <= to_integer(unsigned(IR(11 downto 8))) when etat = ecrireMemoire else
to_integer(unsigned(IR(3 downto 0)));
charge <= '1' when etat = opUAL or etat = lireMemoire else '0';
op <= to_integer(unsigned(IR(14 downto 12)));
Exemple 9-7 – unité de contrôle du processeur général – signaux de contrôle
L’assignation de valeurs aux différents signaux de contrôle est faite à l’aide d’énoncés concurrents à
l’extérieur d’un processus. On s’assure ainsi de ne pas instancier de loquet sur chacun de ces signaux. Les
signaux de contrôle dépendent soit de l’état courant de la machine, de la valeur du registre des instructions, ou des deux. En observant le Tableau 9-2, on constate que l’adresse de la mémoire des données est
contenue dans les bits 7 à 0 du registre d’instructions, sauf pour les instructions concernant l’UAL. Cependant, comme la sortie de la mémoire n’est pas sollicitée dans ce cas, on peut se permettre de simplifier
la description et ne pas inclure de condition en rapport avec l’état de la machine.
9.4
Exemple de programme
Le processeur décrit plus haut est capable d’exécuter des programmes relativement complexes. Par
exemple, considérons un programme qui consiste à calculer la différence absolue de deux valeurs. Supposons que la première valeur soit entreposée à l’adresse 0 en mémoire, et la deuxième à l’adresse 1. La
différence absolue doit être gardée à l’adresse 3. Le programme montré au Tableau 9-5 pourrait effectuer
cette tâche.
instruction
bits 15-12
bits 11-8
bits 7-4
bits 3-0
R0 ← M[0]
8
0
0
0
R1 ← M[1]
8
1
0
1
R12 ← R0 – R1
1
C
0
1
JPos 5
C
4
0
5
R12 ← R1 – R0
1
C
1
0
M[3] ← R12
9
C
0
3
F
-
-
-
STOP
Tableau 9-5 – programme qui calcule la différence absolue
L’écriture directe d’un programme en codes de 16 bits est ardue. Pour simplifier la tâche, on peut utiliser
un programme spécial appelé assembleur qui donne automatiquement les codes numériques des instructions à partir de leur représentation symbolique. Pour les programmes très complexes, cependant, on utilise plutôt un compilateur qui accepte en entrée un programme dans un langage de haut niveau comme C
ou Python et qui produit les codes des instructions. Le compilateur doit s’appuyer sur une connaissance
approfondie des instructions pouvant être réalisées par le processeur ainsi que des architectures de son
chemin des données et de son unité de contrôle.
9.5
Accélération d’un processeur
Le processeur à usage général décrit dans ce chapitre exécute une instruction en trois cycles d’horloge,
avec un débit d’instructions (instruction throughput) égal à 0.33 instruction par cycle. On pourrait aug-
INF3500 : Conception et réalisation de systèmes numériques
163
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
menter ce débit en ajoutant des registres de pipeline dans le chemin des données et l’unité de contrôle. En
effet, rien n’empêche le processeur d’aller quérir la prochaine instruction à exécuter pendant qu’il décode
l’instruction présente. De plus, il pourrait très bien être simultanément en train d’exécuter l’instruction
précédente. De cette façon, le débit des instructions serait triplé à 1 instruction par cycle, même si la latence de chaque instruction resterait à 3 cycles.
Pour déterminer la fréquence maximale d’horloge, il faudrait mesurer la somme des délais sur le chemin
critique du processeur, tel que discuté à la section 8.3. On pourrait découvrir qu’une section du processeur
est beaucoup plus lente que les autres, par exemple l’UAL. On pourrait alors ajouter des registres de pipeline à l’intérieur de cette section en rajoutant des cycles à certaines instructions.
Une autre amélioration nécessiterait l’instanciation de plusieurs UAL dans le bloc des données. L’unité de
contrôle pourrait alors répartir plusieurs instructions à la fois sur les UAL disponibles. Le débit des instructions serait alors supérieur à une instruction par cycle. On appelle ce genre de processeur un processeur superscalaire. La performance de ce genre de processeur dépend grandement de la dépendance des
données dans le flux des instructions. De façon à augmenter les chances de pouvoir exécuter plusieurs
instructions simultanément, les architectures à très long mot d’instruction (Very Long Word Instruction –
VLIW) comptent sur le travail du compilateur pour composer des groupes d’instructions pouvant être exécutées en parallèle.
Un processeur moderne peut donc à tout moment être en train d’exécuter des dizaines d’instructions simultanément.
9.6
Exercices
1. Considérez le processeur à usage général décrit dans ce chapitre. Donnez trois options pour modifier
le processeur afin de permettre de supporter plus de 8 opérations de l’UAL.
2. Considérez le processeur à usage général décrit dans ce chapitre. Proposez une modification à
l’instruction JUMP pour pouvoir effectuer un branchement vers une adresse exprimée sur plus de 8
bits.
3. Considérez le processeur à usage général décrit dans ce chapitre. Ajoutez une instruction pour pouvoir lire une donnée externe, de la forme Rk ← entreeExterne. Ajoutez un signal de contrôle en entrée, entreeExterneValide, qui prend une valeur de 1 quand l’entrée externe est prête à être
lue. Quand il exécute cette instruction, le processeur doit ‘geler’ tant que l’entrée externe n’est pas valide.
4. Considérez le processeur à usage général décrit dans ce chapitre. Ajoutez une instruction pour pouvoir écrire une donnée externe, de la forme sortieExterne ← Rk. Ajoutez un signal de contrôle en sortie, sortieExterneValide, qui est mis à ‘1’ quand la sortie externe est prête à être lue.
5. Considérez le processeur à usage général décrit dans ce chapitre. Ajoutez une instruction de la forme
Rk ← #XY, permettant de charger un registre avec une valeur constante de 8 bits de large, spécifiée
dans le programme. Utilisez le signal constante en entrée au multiplexeur qui détermine l’entrée
du bloc des registres.
6. Considérez le processeur à usage général décrit dans ce chapitre. Ajoutez une instruction de la forme
Rk ← #WXYZ, permettant de charger un registre avec une valeur constante de 16 bits de large, spécifiée dans le programme. Dans le flot des instructions, la constante serait entreposée immédiatement
après l’instruction de chargement. Il faudrait alors incrémenter le compteur de programme deux fois.
Utilisez le signal constante en entrée au multiplexeur qui détermine l’entrée du bloc des registres.
7. Considérez le processeur à usage général décrit dans ce chapitre. Donnez les instructions et les codes
numériques d’un programme qui calcule la moyenne de 8 valeurs gardées en mémoire dans des cellules contigües à partir de l’adresse 0.
INF3500 : Conception et réalisation de systèmes numériques
164
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
8. Considérez le processeur à usage général décrit dans ce chapitre. Donnez les instructions et les codes
numériques d’un programme qui multiplie deux nombres non signés de 8 bits.
9. Le processeur à usage général décrit dans ce chapitre est basé sur une architecture Harvard, c'est-àdire que les mémoires des données et des instructions sont séparées.
a. Quels sont les avantages et désavantages de cette architecture?
b. Quelles modifications à l’unité de contrôle seraient nécessaires pour implémenter une architecture
Von Neumann, où une seule mémoire est utilisée?
c. Quelles seraient les conséquences des modifications sur les accélérations possibles du processeur,
discutées à la section 9.5?
INF3500 : Conception et réalisation de systèmes numériques
165
v. 2.5, juillet 2013
Chapitre 9 : Conception et réalisation de processeurs à usage général
INF3500 : Conception et réalisation de systèmes numériques
166
v. 2.5, juillet 2013
Chapitre 10 Annexe : Revue des systèmes numériques
Ce chapitre revoit les principes de base des systèmes numériques. Le matériel de ce chapitre est tiré des
notes du cours INF1500.
10.1
Variables booléennes
À la base des systèmes numériques on retrouve la logique booléenne. Dans un système numérique, tous
les signaux sont effectivement des variables booléennes. Une variable booléenne peut prendre une seule
de deux valeurs: vrai ou faux. On peut interpréter ces deux valeurs de différentes façons selon le contexte.
Quelques exemples sont donnés au Tableau 10-1. En général, on utilise l’interprétation numérique.
valeur
logique
équivalent
numérique
ex. : lampe
ex : tension
ex : alarme
vrai
1
allumée
élevée
activée
faux
0
éteinte
basse
désactivée
Tableau 10-1 - exemples de valeurs booléennes
10.2
Fonctions booléennes, symboles et tables de vérité
Il y a trois fonctions booléennes de base, l’inversion, le ET logique et le OU logique. Plusieurs fonctions
peuvent être dérivées de ces trois fonctions de base, comme le NON-OU, le NON-ET, le OU-exclusif et
l’équivalence. Ces fonctions sont montrées au Tableau 10-2.
Une fonction booléenne peut être représentée de trois façons : soit par une notation algébrique, soit par un
symbole, soit par une table de vérité. Ces représentations sont aussi montrées au Tableau 10-2.
On peut écrire une expression booléenne complexe en combinant plusieurs variables et constantes ainsi
que les opérations NON, ET, OU. La préséance des opérations est similaire à l’arithmétique habituelle,
soit : les parenthèses, l’inversion, le ET puis le OU.
Une table de vérité spécifie la valeur d’une expression booléenne pour toutes les combinaisons possibles
des valeurs des variables qui la composent. On établit en général la liste des combinaisons possibles des
variables dans un ordre croissant selon leur code binaire correspondant. La table de vérité d’une expression à n variables contient 2n rangées.
On dit que deux expressions booléennes sont égales si elles ont la même valeur pour toutes les combinaisons d’entrées possibles, donc si leurs tables de vérité sont identiques.
INF3500 : Conception et réalisation de systèmes numériques
167
v. 2.42, décembre 2009
Chapitre 10 : Annexe : Revue des systèmes numériques
fonction
notation
algébrique
NON
(NOT)
F  A
« inversion »
ou « complément »
A
 A
F  AB
ET
(AND)
OU
(OR)
NON-OU
(NOR)
NON-ET
(NAND)
OU-exclusif
(XOR)
équivalence
 A B
symbole
A
A
B
F
A
B
F  A B
A
B
F  AB
A
B
F  A B
A
B
F  A B
A
B
A
0
1
F
 A B
F  A B
 A B
table de vérité
F
F
F
F
F
F
1
0
A
B
F
0
0
1
1
0
1
0
1
0
0
0
1
A
0
0
1
1
B
0
1
0
1
F
0
1
1
1
A
B
F
0
0
1
1
0
1
0
1
1
0
0
0
A
B
F
0
0
1
1
0
1
0
1
1
1
1
0
A
B
F
0
0
1
1
0
1
0
1
0
1
1
0
A
B
F
0
0
1
1
0
1
0
1
1
0
0
1
Tableau 10-2 - fonctions logique de base
INF3500 : Conception et réalisation de systèmes numériques
168
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
10.3
Algèbre booléenne
À partir de la définition des fonctions booléennes de base, on peut vérifier les équivalences suivantes, qui
peuvent permettre de manipuler est simplifier des expressions booléennes. Ces règles sont tirées de Roth,
5e éd.
règles de base
1. X + 0 = X
1D. X • 1 = X
2. X +1 = 1
2D. X • 0 = 0
3. X + X = X
3D. X • X = X
4. (X')' = X
5D. X • X' = 0
5. X + X' = 1
commutativité, associativité et distributivité
6:X+Y=Y+X
6D : XY = YX
7 : (X + Y) + Z = X + (Y + Z)
7 D: (XY)Z = X(YZ)
8 : X(Y + Z) = XY + XZ
8D : X + YZ = (X + Y)(X + Z)
règles de simplification
9. XY + XY' = X
9D. (X + Y)(X + Y') = X
10. X + XY = X
10D. X(X + Y) = X
11. (X + Y')Y = XY
11D. XY' + Y = X + Y
théorème de De Morgan
12. (X + Y + Z +...)' = X'Y'Z'...
12D. (XYZ...)' = X' + Y' + Z' +...
théorème de la dualité
13. (X + Y + Z +...)D = XYZ...
13D. (XYZ...)D = X + Y + Z +...
factorisation
14. (X + Y)(X' + Z) = XZ + X'Y
14D. XY + X'Z = (X + Z)(X' + Y)
théorème du consensus
15. XY + YZ + X'Z = XY + X'Z
10.4
15D. (X + Y)(Y + Z)(X' + Z) = (X + Y)(X' + Z)
Formes canoniques et expansion en mintermes et maxtermes
À partir d’une table de vérité, on peut facilement donner la valeur de la fonction logique correspondante
par l’une des deux formes canoniques : une somme de produits ou un produit de sommes.
Pour obtenir la somme de produits, on énumère les termes de la fonction qui correspondent à une valeur
de 1 de celle-ci. Chaque terme est composé d’un produit (ET logique) de chaque variable de la fonction.
Une variable ayant la valeur 0 dans la rangée correspondante est complémentée.
Pour obtenir le produit des sommes, on énumère les termes de la fonction qui correspondent à une valeur
de 0 de celle-ci. Chaque terme est composé d’une somme (OU logique) de chaque variable de la fonction.
Une variable ayant la valeur 1 dans la rangée correspondante est complémentée.
Chaque terme dans l’expansion en somme de produits est un minterme, dénoté par mi, où i est le numéro
de la rangée correspondante à ce terme.
INF3500 : Conception et réalisation de systèmes numériques
169
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
Chaque terme dans l’expansion en produit de sommes est un maxterme, dénoté par Mi, où i est le numéro
de la rangée correspondante à ce terme.
Le tableau suivant donne l’expression des mintermes et maxtermes pour une fonction à trois variables :
#
A
B
C
mi
Mi
0
0
0
0
m0 = A’ B’ C’
M0 = A + B + C
1
0
0
1
m1 = A’ B’ C
M1 = A + B + C’
2
0
1
0
m2 = A’ B C’
M2 = A + B’ + C
3
0
1
1
m3 = A’ B C
M3 = A + B’ + C’
4
1
0
0
m4 = A B’ C’
M4 = A’ + B + C
5
1
0
1
m5 = A B’ C
M5 = A’ + B + C’
6
1
1
1
1
0
1
m6 = A B C’
m7 = A B C
M6 = A’ + B’ + C
M7 = A’ + B’ + C’
7
Observations :

On constate que les index présents dans la somme de mintermes ne le sont pas dans le produit de
maxtermes, et vice-versa.

On observe que mi = Mi’.

Pour obtenir une fonction, on prend la somme des mintermes où la fonction vaut 1, ou le produit des
maxtermes où la fonction vaut 0.

Pour obtenir l’inverse d’une fonction, on prend la somme des mintermes où la fonction vaut 0, ou le
produit des maxtermes où la fonction vaut 1.
10.5
Simplification d’expressions booléennes à l’aide de tables de Karnaugh
Une table de Karnaugh est une façon compacte de représenter une table de vérité. Les tables de Karnaugh
permettent de simplifier facilement et méthodiquement des expressions booléennes.
On note :

Chaque case de la table de Karnaugh correspond à une rangée de la table de vérité.

Un ‘1’ placé dans une case de la table de Karnaugh correspond à un minterme de la fonction.

Un ‘0’ placé dans une case de la table de Karnaugh correspond à un maxterme de la fonction.

Deux mintermes ou maxtermes représentés par deux cases adjacentes ne diffèrent que par un seul bit.
Les exemples suivants présentent des tables de Karnaugh à 2, 3 et 4 variables. Des versions à 5 et 6 variables sont aussi possibles. Au-delà de 6 variables, il faut utiliser des tables séparées, et leur utilité est
douteuse.
La numérotation des colonnes et des rangées des tables de Karnaugh est critique : un seul bit varie entre
deux colonnes ou entre deux rangées.
INF3500 : Conception et réalisation de systèmes numériques
170
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
#
A
0
1
2
3
B
0
0
1
1
A
F
0
1
0
1
B
1
0
1
1
F(A, B)
0
0
1
1
1
0
1
2
0
1
1
#
A
B
C
F
0
1
2
3
4
5
6
7
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
1
1
1
0
0
1
0
AB
C
F(A, B, C)
00
0
01
0
1
A
B
C
D
F
1
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0
0
0
0
0
0
0
0
1
1
1
1
1
1
1
1
0
0
0
0
1
1
1
1
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
1
1
0
0
1
0
0
0
1
0
1
0
1
1
AB
CD
01
0
0
5
1
0
1
0
0
1
9
0
15
1
6
8
13
7
1
2
0
12
5
0
1
10
1
4
3
10
4
7
11
0
1
11
0
3
0
01
0
6
F(A, B, C, D)
00
00
10
1
2
1
#
11
1
0
1
3
11
1
14
10
10.5.1 Impliquants
Quelques définitions :

Adjacence : Deux cellules sont adjacentes si elles se touchent ou si elles sont à deux extrémités de la
table (i.e. la cellule du haut et la cellule du bas d’une colonne sont adjacentes, et la cellule de gauche
et la cellule de droite d’une rangée sont adjacentes aussi).
INF3500 : Conception et réalisation de systèmes numériques
171
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques

Impliquant : Un groupe de forme rectangulaire de 1, 2, 4, 8, 16, 32, 64, … 2k, k  N, cellules adjacentes contenant des ‘1’.

Impliquant primaire : Impliquant ne pouvant pas être combiné avec un autre impliquant pour former
un impliquant plus grand.

Impliquant primaire essentiel : Si un minterme est couvert par un seul impliquant primaire, cet impliquant est qualifié d’essentiel. Il fera partie de la description minimale de la fonction.
10.5.2 Procédure de simplification d’équations booléennes
La procédure pour obtenir une somme de produits se résume en deux étapes :
10. former des impliquants contenant le plus de ‘1’ possible; et,
11. trouver un nombre minimal d’impliquants couvrant tous les ‘1’.
Pour obtenir un produit de sommes, on suit la même procédure en considérant les ‘0’.
10.5.3 Fonctions définies partiellement: valeurs sans importance
Nous avons supposé que la valeur des fonctions logiques devait être spécifiée exactement pour chaque
entrée possible. En pratique, ce n’est pas toujours nécessaire. Si une combinaison de variables d’entrée est
impossible, alors on « se fiche » (don’t care) de la valeur que la fonction pourrait prendre dans ce cas.
Cette valeur est sans importance, puisqu’on considère qu’elle ne peut survenir. On indique ces situations
par un ‘X’ ou un tiret (-) dans la table de vérité et dans la table de Karnaugh de la fonction. Il est préférable d’utiliser le tiret pour éviter la confusion avec le nom de variable ‘X’.
Comme la combinaison d’entrées correspondant à un ‘-’ est impossible, on peut assigner la valeur ‘0’ ou
‘1’ à ce ‘-’, comme bon nous semble. Dans la table de Karnaugh, si ce ‘-’ permet de combiner un plus
grand nombre de ‘1’ ensemble, on l’interprète comme un ‘1’. Sinon, on l’interprète comme un ‘0’.
10.6
Autres fonctions logiques
Il y a 16 possibilités de fonctions logiques à deux variables x et y, tel que montré dans la table de vérité
combinée suivante.
Les fonctions F0 et F15 sont des constantes, alors que les fonctions F3, F5, F10 et F12 se réduisent à des
fonctions à une seule variable. Il ne reste donc que 10 fonctions de deux variables proprement dites.
x
y
Fo
F1
F2
F3
F4
F5
F6
F7
F8
F9
F10
F11
F12
F13
F14
F15
0
0
0
0
0
0
0
0
0
0
1
1
1
1
1
1
1
1
0
1
0
0
0
0
1
1
1
1
0
0
0
0
1
1
1
1
1
0
0
0
1
1
0
0
1
1
0
0
1
1
0
0
1
1
1
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
Les portes logiques à une et deux entrées les plus usitées sont données ici. Les portes sont organisées en
deux colonnes, selon qu’il y ait ou non un symbole d’inversion (une bulle) à la sortie. Le symbole
d’inversion peut toujours être remplacé par un inverseur.
INF3500 : Conception et réalisation de systèmes numériques
172
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
X
X
(identité)
X
X
X
X+Y
(OU, OR)
Y
X
Y
X
XY
(ET, AND)
Y
X
Y
X
X+Y
(OU-exclusif, différence,
OUX, XOR)
Y
Y
X’
(inversion, NON, NOT)
(X + Y)’
(NON-OU, NOR)
(XY)’
(NON-ET, NAND)
(X + Y)’
(coïncidence,
équivalence)
On peut aussi placer le symbole d’inversion à l’une ou aux deux entrées de la porte logique (ainsi qu’à sa
sortie). On obtient alors plusieurs combinaisons possibles, dont en voici quatre exemples. On peut démontrer des équivalences entre ces portes grâce à la logique booléenne.
X
Y
X
Y
X
X’ + Y
Y
X
X’ + Y’
Y
(X’Y)’
(X’Y’)’
Toutes les portes logiques, sauf le NON et l’identité, peuvent avoir plus de deux entrées. En voici
quelques exemples :
A
B
C
D
A
B
C
10.7
ABCD
A
B
C
(ABC)'
A+B+C
A
B
C
(A+B+C)'
Délais et chronogrammes
On a supposé à date que les signaux se propageaient à travers les circuits à une vitesse infinie. Ce n’est
pas le cas. Quand l’entrée d’une porte logique change, un changement ne se propagera pas instantanément
INF3500 : Conception et réalisation de systèmes numériques
173
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
à la sortie. Les transistors, résistances, condensateurs et autres éléments électroniques à l’intérieur de la
porte prennent un certain temps à réagir.
Un chronogramme (timing diagram) permet d’observer les signaux d’un circuit en fonction du temps.
Par exemple, considérons le circuit suivant, où les délais de chaque porte logique sont indiqués.
5 ns
A
B
C
2.5 ns
D
5 ns
F
Le chronogramme suivant suppose deux signaux d’entrées A et B, et indique la valeur des signaux intermédiaires C et D ainsi que la sortie F en fonction du temps.
A
B
C
D
F
0
10.8
5
10
15
20
25
30
35
40
45
(ns)
Codes numériques et alphanumériques
10.8.1 Nombres entiers
Dans le domaine des systèmes numériques, les bases les plus utilisées sont les bases 2, 8, 10 et 16. À
l’intérieur du système lui-même, la base 2 est utilisée à cause de sa correspondance directe à la logique
booléenne. Le tableau suivant illustre la représentation des 16 premiers nombres entiers selon ces bases.
Pour représenter les nombres entiers signés en base deux, l’approche la plus utilisée dans les systèmes
numériques est la représentation en complément à deux. Pour ce système, le bit le plus significatif indique
le signe du nombre : 0 pour positif et 1 pour négatif. Pour les nombres positifs, il est donc essentiel de
toujours ajouter un ‘0’ en position la plus significative. Pour multiplier un nombre binaire en complément
à 2 par -1, on complémente chaque bit du nombre et on ajoute ‘1’.
Avec n bits, la gamme des nombres entiers signés pouvant être représentés est de (2n1) à 2n1  1.
INF3500 : Conception et réalisation de systèmes numériques
174
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
base
10
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
base
2
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
base
8
0
1
2
3
4
5
6
7
10
11
12
13
14
15
16
17
base
16
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
10.8.2 Codes alphanumériques
Les systèmes numériques sont souvent appelés à traiter de l’information textuelle, c’est-à-dire qui est
composée de caractères. Il est donc nécessaire de pouvoir représenter ces caractères sous forme numérique. Il y a quatre classes principales de caractères à représenter :

les lettres, e.g. q, w, E, r, T, t, à, É, ü, ì, Ç, , , , Œ, Ю, Я, ‫ی‬, ‫ڥ‬, ‫ٽ‬, etc.;

les chiffres, e.g. 0, 1, 2, 3, 4, 5, 6, 7, 8 et 9;

les caractères typographiques, e.g. !, @, /, $, %, ?, ,, (, , , , etc.; et,

les caractères de contrôle non-imprimables, e.g. « start-of-text », « line-feed », « carriage-return »,
etc.
Pour représenter tous ces caractères, on utilise un code standardisé qui associe un nombre à chaque caractère alphanumérique.
Une possibilité est le code Unicode à 16 bits (voir http://www.unicode.org/). Il y a donc 65536 codes
possibles, ce qui permet de représenter la plupart des symboles des alphabets de la planète et plusieurs
caractères spéciaux. Cependant, il n’y a pas assez de codes disponibles pour représenter tous les idéogrammes des langues d’Asie.
Le code Unicode est basé sur le code ASCII (American Standard Code for Information Interchange). La
version originale du code ASCII ne comportait que 128 symboles. La version étendue en comporte 256.
Les 256 premiers symboles du code Unicode sont identiques au code ASCII étendu. Une partie du code
ASCII de base est donnée au tableau 1-3, Roth 5e, p. 22. Voir aussi http://fr.wikipedia.org/wiki/ASCII.
Il est important de remarquer que les nombres ont une représentation différente s’ils sont encodés par leur
valeur ou par leur représentation textuelle. Par exemple, le nombre 5 (000001012) a une représentation
différente du caractère ‘5’ (ASCII 001101012 = 5310).
Plusieurs codes ont aussi été définis pour encoder uniquement des chiffres. Certains codes sont pondérés,
d’autres non. Les plus connus sont illustrés au tableau suivant.
INF3500 : Conception et réalisation de systèmes numériques
175
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
10.9
chiffre
décimal
code
8-4-2-1
(BCD)
code
6-3-1-1
code
Excess-3
code
2-de-5
code Gray
0
0000
0000
0011
00011
0000
1
0001
0001
0100
00101
0001
2
0010
0011
0101
00110
0011
3
0011
0100
0110
01001
0010
4
0100
0101
0111
01010
0110
5
0101
0111
1000
01100
1110
6
0110
1000
1001
10001
1010
7
0111
1001
1010
10010
1011
8
1000
1011
1011
10100
1001
9
1001
1100
1100
11000
1000
Éléments à mémoire de base
Cette section décrit trois éléments à mémoire de base : le loquet SR, le loquet D et la bascule D.
10.9.1 Loquet SR
Un loquet SR (S-R latch) est un élément à mémoire simple mais fondamental. Il peut rester dans un état
tant qu’on l’alimente, et sa sortie dépend non seulement des entrées présentes, mais aussi des entrées passées. Le loquet SR est très rarement utilisé par lui-même dans les circuits séquentiels, mais il fait souvent
partie de composantes plus complexes.
Un loquet SR peut être formé de deux portes NON-OU en connectant leurs sorties à l’entrée de l’autre
porte. Les deux ports d’entrée restants sont appelés « S » et « R », pour « set » et « reset ».
circuit
symbole
S
Q'
S
R
Q
R Q'
Q
Figure 10-1 – loquet SR
Pour ce circuit, la sortie future Q(t + 1) dépend des valeurs des entrées présentes S(t) et R(t), ainsi que de
la valeur de la sortie présente de Q(t). Le tableau caractéristique et l’équation caractéristique du loquet SR
sont donnés à la Figure 10-2.
INF3500 : Conception et réalisation de systèmes numériques
176
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
tableau caractéristique
S(t)
R(t)
Q(t)
Q(t + 1)
Q’(t + 1)
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
1
0
0
1
1
0
0
1
0
1
1
0
0
0
0
équation
mode
mémoire
reset
Q(t  1)  S (t )  R(t )Q(t ), SR  0
set
interdit
Figure 10-2 – tableau et équation caractéristiques du loquet SR
La combinaison d’entrées S = R = 1 est interdite, et mène à un état illégal, puisque alors on aurait Q(t+1)
= 0 et Q’(t+1) = 0. De plus, si les entrées S et R passent simultanément de 1-1 à 0-0, on ne sait pas sur
quel état le loquet va se stabiliser. On impose donc la condition SR = 0.
Le chronogramme de la Figure 10-3 illustre le comportement du loquet SR.
S
R
Q
Q’
Figure 10-3 – exemple de chronogramme d’un loquet SR
10.9.2 Loquet D
Le loquet D (Dlatch) est le type de loquet le plus commun. Il a deux entrées : un signal de données D et
un signal de contrôle G (Gate). Il a deux états : transparent et mémoire, déterminés par la valeur de G (1
et 0 respectivement). Contrairement au loquet SR, le loquet D n’a pas de restrictions sur les valeurs acceptables des entrées.
Le loquet D peut être construit à partir d’un loquet SR, de deux portes ET et d’un inverseur, connectés de
façon à éliminer la combinaison interdite 1-1 pour les entrées du loquet SR. Ceci est illustré à la Figure
10-4. Le tableau caractéristique et l’équation caractéristique du loquet D sont donnés à la Figure 10-5.
INF3500 : Conception et réalisation de systèmes numériques
177
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
circuit
symbole
D
Q
D Q
R Q'
G Q'
S
G
Figure 10-4 – loquet D
tableau caractéristique
G(t)
D(t)
Q(t)
Q(t + 1)
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
1
0
1
0
0
1
1
équation
mode
mémoire
Q(t  1)  G (t )Q(t )  G (t ) D(t )
transparent
Figure 10-5 – tableau et équation caractéristiques du loquet D
Le chronogramme de la Figure 10-6 illustre le comportement du loquet D.
G
D
S
R
Q
Figure 10-6 – exemple de chronogramme d’un loquet D
10.9.3 Bascule D : synchronisation sur une transition d’horloge
Le loquet D a le désavantage d’avoir un mode « transparent ». Si on place plusieurs loquets D en série et
qu’on les mène par le même signal de contrôle G, un signal appliqué au premier loquet pourra se propager
à travers tous les autres. Pour éviter cette situation, il est souhaitable de réduire la durée du mode « transparent » à un très bref instant pendant une transition du signal de contrôle. Le circuit résultant s’appelle
une bascule.
INF3500 : Conception et réalisation de systèmes numériques
178
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
La bascule D (D flip-flop) est le type d’élément à mémoire de loin le plus commun. Elle a deux entrées :
un signal de données D et une horloge CLK (clock). Contrairement au loquet D, la bascule D n’a pas de
mode transparent – l’entrée D est saisie sur une transition de l’horloge. La bascule D peut être construite
en cascadant deux loquets D en configuration « maître-esclave » et en alimentant chaque loquet avec des
versions complémentaires d’un signal d’horloge. Cette configuration est montrée à la Figure 10-7.
circuit
D
D1 Q1
symbole
P
D2 Q2
Q
D
Q
CLK
CLK
G1
G2
Q’
Q'
Figure 10-7 – bascule D
Le chronogramme de la Figure 10-8 permet de constater que, pour ce circuit, l’entrée globale D se propage à la sortie Q uniquement sur une transition positive de l’horloge.
CLK
D
G1
Q1 = P
G2
Q2 = Q
Figure 10-8 – exemple de chronogramme d’une bascule D
INF3500 : Conception et réalisation de systèmes numériques
179
v. 2.5, juillet 2013
Chapitre 10 : Annexe : Revue des systèmes numériques
INF3500 : Conception et réalisation de systèmes numériques
180
v. 2.5, juillet 2013
Bibliographie
G. Antoniol, LOG2430 – notes de cours, École Polytechnique de Montréal, 2006.
J. Bhasker, A VHDL Primer, 3e éd., Prentice-Hall, 1999.
ISBN: 0-13-096575-8
J. Bhasker, A VHDL Synthesis Primer, 2e éd., Star Galaxy Publishing, 1998.
ISBN: 0-9650391-9-6
D. Dempster et M. Stuart, Verification Methodology Manual - Techniques for Verifying HDL Designs,
3rd Ed., Teamwork International, 2002.
ISBN ISBN 0-9538-4822-1
[En ligne]. Disponible: http://www.edacafe.com/books/TransEDA/ [Consulté le 27 août 2009].
IEEE Computer Society, IEEE Standard VHDL Language Reference Manual (1076-2002), Institute of
Electrical and Electronics Engineers, Inc., 2002.
ISBN: 0-7381-3247-0, 0-7381-3248-9
IEEE Computer Society, IEEE Standard for VHDL Register Transfer Level (RTL) Synthesis (1076.62004), Institute of Electrical and Electronics Engineers, Inc., 2004.
ISBN: 0-7381-4064-3, 0-7381-4065-1
J.L Hennessy et D.A. Patterson, Computer architecture: a quantitative approach, 3rd edition, Morgan
Kaufmann, 2002.
ISBN: 1558605967
W. K. Lam, Hardware Design Verification, Prentice-Hall, 2005.
ISBN: 0-13-143347-4
S. Kilts, “Advanced FPGA Design,” Wiley, 2007.
ISBN: 978-0-470-05437-6
J. Lewis, “VHDL Math Tricks of the Trade,” MAPLD 2003. [En ligne]. Disponible:
http://www.synthworks.com/papers/index.htm. [Consulté le 3 juin 2009].
X. Maldague, Circuits logiques, Loze-Dion, 2006.
ISBN : 2-921180-85-5
M.M. Mano et C.R. Kime, Logic and Computer Design Fundamentals, 2e éd., Prentice-Hall, 2001.
ISBN: 0-13-031486-2
C. Maxfield, The Design Warrior’s Guide to FPGAs: Devices, Tools and Flows, Newnes/Elsevier, 2004.
ISBN: 0-7506-7604-3
C.H. Roth, Fundamentals of Logic Design, 5e éd., Brookes/Cole, 2004.
ISBN: 0-534-37804-8
D.J. Smith, HDL Chip Design, Doone Publications, 1996.
ISBN: 0-9651934-3-8
M.J.S. Smith, Application-Specific Integrated Circuits, Addison Wesley Longman, 1997.
ISBN: 0-201-50022-1
F. Vahid, Digital Design, Wiley, 2007.
ISBN: 978-0-470-04437-7
F. Vahid et R. Lysecky, VHDL for Digital Design, Wiley, 2007.
ISBN: 978-0-470-05263-1
INF3500 : Conception et réalisation de systèmes numériques
181
v. 2.5, juillet 2013
J.F. Wakerly, Digital Design : Principles and Practices, 4e éd., Pearson Prentice-Hall, 2006.
ISBN: 0-13-186389-4
Xilinx inc., XST User Guide 8.1i, 2005.
S. Yalamanchili, Introductory VHDL: From Simulation to Synthesis, Prentice-Hall, 2001.
ISBN: 0-13-080982-9
M. Zwolinski, Digital System Design with VHDL, 2e éd., Pearson Prentice-Hall, 2004.
ISBN: 0-13-039985-X
INF3500 : Conception et réalisation de systèmes numériques
182
v. 2.5, juillet 2013