188
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.

INF3500 Conception et réalisation de systèmes … · 2.5 Quelques détails du langage VHDL ... 3.8 Exercices ... condensateurs et inductances. Le cours INF3500 concerne principalement

Embed Size (px)

Citation preview

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

INF3500 : Conception et réalisation de systèmes numériques i v. 2.5, juillet 2013

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

Table des matières

INF3500 : Conception et réalisation de systèmes numériques ii v. 2.5, juillet 2013

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

Table des matières

INF3500 : Conception et réalisation de systèmes numériques iii v. 2.5, juillet 2013

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

Table des matières

INF3500 : Conception et réalisation de systèmes numériques iv v. 2.5, juillet 2013

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 1 v. 2.42, décembre 2009

Chapitre 1 Introduction

1.1 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 cal-

culatrices 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 pres-

sion 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.

Chapitre 1: Introduction

INF3500 : Conception et réalisation de systèmes numériques 2 v. 2.5, juillet 2013

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.

1.2 Niveaux d’abstraction des systèmes numériques

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 impor-

tances relatives dépendent grandement de l’application visée, alors elles sont présentées ici en ordre al-

phabétique :

La précision des calculs: La précision requise pour les calculs effectués est dictée par la bande dyna-

mique 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 ther-

mique 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.

Chapitre 1: Introduction

INF3500 : Conception et réalisation de systèmes numériques 3 v. 2.5, juillet 2013

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 pos-

sibilité 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 embar-

qué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 Cir-

cuit, 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 fonc-

tions 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 con-

cevoir 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 com-

plexes.

Chapitre 1: Introduction

INF3500 : Conception et réalisation de systèmes numériques 4 v. 2.5, juillet 2013

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 ni-

veaux 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 per-

formance 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 particu-

lier.

Technologies de circuits intégrés à application spécifique (ASIC)

Logique fixe Logique programmable

ASIC sur mesure

Full-custom ASIC

ASIC à cellules normalisées

Cell-based ASIC

réseau pré-diffusé de portes

Gate Array

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 5 v. 2.42, décembre 2009

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 modi-

fier. 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 popula-

rité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 diffi-

ciles à 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 Lan-

guage (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 directe-

ment, tel que montré dans l’Exemple 2-1.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 6 v. 2.5, juillet 2013

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;

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;

X

Y

CinS

Cout

T1

T2

T3

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 cir-

cuit.

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éfi-

nit 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 :

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 7 v. 2.5, juillet 2013

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écla-

rative, 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é à la-

quelle 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 suffi-

samment 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 ‘<=’ signi-

fie 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.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 8 v. 2.5, juillet 2013

2.3 Trois styles de description du comportement d’un circuit

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 sui-

vantes.

É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éra-

teurs 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;

architecture flotDeDonnees1 of combinatoire1 is

begin

F <= not(A and (B xor not(C)));

end flotDeDonnees1;

A

B

C

F

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 expres-

sion. 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 cir-

cuit avec l’équivalent d’une table de vérité. L’énoncé with-select permet d’assigner une valeur à un

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 9 v. 2.5, juillet 2013

signal selon différentes valeurs d’une expression de sélection. Les différents choix doivent être mutuelle-

ment 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 pro-

grammation 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 B C F

0 0 0 1

0 0 1 1

0 1 0 1

0 1 1 1

1 0 0 0

1 0 1 1

1 1 0 1

1 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, combi-

nant 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 illus-

tré 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-then-

else. 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

B

C

F

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 sym-

bole ‘<=’ 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.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 10 v. 2.5, juillet 2013

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 des-

cription 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 compo-

santes 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 compi-

lation 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 mon-

tré 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 assigna-

tions concurrentes à des signaux sont réputées se produire simultanément.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 11 v. 2.5, juillet 2013

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 cir-

cuits numériques. En effet, il est alors possible d’abstraire le comportement du circuit à un très haut ni-

veau, 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 dispo-

nibles 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 con-

currente à 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 fonc-

tions 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écri-

vent 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 as-

signe 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 proces-

sus. Dans le cas montré ici, la partie déclarative du processus est vide.

-- assignation concurrente

F <= not(A and (B xor not(C)));

-- utilisation d’un processus

process (A, B, C)

begin

F <= not(A and (B xor not(C)));

end process;

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 va-

leurs 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

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 12 v. 2.5, juillet 2013

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édiate-

ment 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 plu-

sieurs é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.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 13 v. 2.5, juillet 2013

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.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 14 v. 2.5, juillet 2013

library ieee;

use ieee.std_logic_1164.all;

entity basculeD is

port (

CLK : in STD_LOGIC; -- horloge

D : in STD_LOGIC; -- entrée

Q : out STD_LOGIC -- sortie

);

end basculeD;

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;

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 CLK’event and CLK = ‘1’ rising_edge(CLK)

front descendant CLK’event and CLK = ‘0’ 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 syn-

chrone 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.

D

CLK

Q'

Q

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 15 v. 2.5, juillet 2013

library IEEE;

use IEEE.std_logic_1164.all;

entity basculeDR is

port (

reset : in STD_LOGIC; -- signal de remise à zéro

CLK : in STD_LOGIC; -- signal d'horloge

D : in STD_LOGIC; -- entrée

Q : out STD_LOGIC -- sortie

);

end basculeDR;

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 (Dlatch) 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é.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 16 v. 2.5, juillet 2013

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;

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 17 v. 2.5, juillet 2013

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 sys-

tè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 carac-

tère doit être une lettre, le dernier ne peut pas être le soulignement, et on ne peut utiliser deux souligne-

ments 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 per-

mettent 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.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 18 v. 2.5, juillet 2013

Une conversion explicite de type est faite en spécifiant le type désiré immédiatement suivi d’une expres-

sion à convertir placée entre parenthèses, tel que démontré dans l’Exemple 2-15.

catégorie type

ou sous-type

source

de la définition valeurs

scalaires

boolean 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 cer-

taines 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)

composés

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

Tableau 2-3 - types les plus communément utilisés pour la synthèse de circuits numériques

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 19 v. 2.5, juillet 2013

variable v1 : real;

variable v2 : integer;

variable v3 : std_logic_vector(3 downto 0) := "1101";

v1 := real(3);

v2 := integer(1.5 * 0.999);

-- v2 := integer("0010"); -- illégal

-- v3 := 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.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 20 v. 2.5, juillet 2013

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.

catégorie opérateurs

type de

l’opérande

de gauche

type de

l’opérande

de droite

type de

l’expression

logique and, or, nand, nor,

xor, xnor, not bit, boolean

relation =, /=, <, <=, >, >= scalaire ou tableau boolean

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)

tableau de

bit ou boolean

integer

comme

l’opérande

de gauche

arithmétique

+, -, *, /,

abs (valeur absolue),

mod (modulo),

rem (reste) type

numérique

type

numérique type

numérique

** (exponentiation) integer

concaténation & 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, mon-

tré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

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 21 v. 2.5, juillet 2013

À 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 peu-

vent 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.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 22 v. 2.5, juillet 2013

Les opérateurs de VHDL peuvent aussi être surchargés en utilisant le nom de l’opérateur comme identifi-

cateur 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 fi-

chiers. 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éfini-

tions 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écla-

ration du package, l’exemple illustre deux définitions de types et une déclaration d’une fonction. Le pack-

age 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

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 23 v. 2.5, juillet 2013

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 dis-

tincts. 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 Active-

HDL, 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 pri-

maires 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, cons-

tantes, 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.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 24 v. 2.5, juillet 2013

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.

Chapitre 2 : Description de circuits numériques avec VHDL

INF3500 : Conception et réalisation de systèmes numériques 25 v. 2.5, juillet 2013

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 fonc-

tionnement à l’aide d’un simulateur. Modifiez votre modèle si nécessaire pour que les entrées inter-

dites 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 énon-

cé generic dans la partie déclarative de l’entité. Simulez votre modèle pour toutes les combinai-

sons 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 fonction-

nement correspond bien à celui d’une bascule.

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

INF3500 : Conception et réalisation de systèmes numériques 27 v. 2.42, décembre 2009

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 logiciel-

maté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 classi-

fiait 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 10

3, et un circuit LSI de l’ordre de 10

4 transistors.

Une famille de circuits SSI/MSI très populaire jusqu’au début des années 1990 était la série 7400. Norma-

lisé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)

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 28 v. 2.5, juillet 2013

Les circuits MSI incluaient entre autres des multiplexeurs, décodeurs, registres et compteurs. Miraculeu-

sement (pour l’époque), leur coût de fabrication n’était pas significativement supérieur à celui des compo-

santes 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 micropro-

cesseurs 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 (Pro-

grammable 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 2n 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 im-

plé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 :

BACmF

BCBAmF

ACBmF

ACBAmF

)7,6,5,3,2(

''')6,2,1,0(

')7,6,4,3,2(

''')6,4,1,0(

3

2

1

0

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 fi-

gure, pour empêcher une ligne horizontale d’en mener une autre par l’entremise de leurs connexions res-

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 29 v. 2.5, juillet 2013

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.

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)

décodeur 4:16

m7

m6

m5

m4

m3

m2

m1

m0

A2

A1

A0

A3

m15

m14

m13

m12

m11

m10

m9

m8

D7

D6

D5

D4

D3

D2

D1

D0

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 30 v. 2.5, juillet 2013

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 re-

prises, 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 hori-

zontales. 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 programma-

tion 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

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 31 v. 2.5, juillet 2013

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’.

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.

F0

A0A1A2

F1F2

A3

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 32 v. 2.5, juillet 2013

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 maxi-

mal d’entrées, le « L » indique que les sorties sont en logique inversée, et le « 8 » donne le nombre maxi-

mal 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.

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 33 v. 2.5, juillet 2013

Figure 3-8 – PAL 16L8

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 34 v. 2.5, juillet 2013

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)

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 35 v. 2.5, juillet 2013

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 macro-

cellule 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.

Figure 3-11 – modèle d’un FPGA

CLB CLB CLB CLB CLB

CLB CLB CLB CLB CLB

CLB CLB CLB CLB CLB

IOB IOB IOB IOB IOB IOB

IOB IOB IOB IOB IOB IOB

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 36 v. 2.5, juillet 2013

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 fonc-

tion en groupant les lignes par paires. À chaque paire de lignes correspond une valeur des lignes de sélec-

tion 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

( , , ) (0,5,6,7)F x y z m . 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

entrée Di valeur

0 0 0 0 1 D0 z’

1 0 0 1 0

2 0 1 0 0 D1 0

3 0 1 1 0

4 1 0 0 0 D2 z

5 1 0 1 1

6 1 1 0 1 D3 1

7 1 1 1 1

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 mul-

tiplexeurs. 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 essen-

tiels 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;

0

zF

0

z’

1

y

x

1

2

3

S1

S0

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 37 v. 2.5, juillet 2013

quatre multiplexeurs dont les signaux de contrôle S0 à S3 sont programmables; et,

deux éléments à mémoire configurables en bascules ou loquets.

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 simi-

laire, 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 re-

groupe 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.

Table de

conversion

G

16 X 1

D

CLK

Q

H

Table de

conversion

F

16 X 1

YQ

Y

XQ

X

G4

G3

G2

G!

F4

F3

F2

F1

H1

S0

S1

S2

S3

D

CLK

Q

CLK

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 38 v. 2.5, juillet 2013

Pour les FPGAs des familles Spartan et Virtex, Xilinx utilise le terme slice pour un module de base in-

cluant 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.

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

Columns of embedded

RAM blocks

Arrays of

programmable

logic blocks

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 39 v. 2.5, juillet 2013

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 les-

quelles 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.

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 con-

siste à 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.

RAM blocks

Multipliers

Logic blocks

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 40 v. 2.5, juillet 2013

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.

Figure 3-17 – processeur intégré

(source : fig. 4-10, Maxfield, © Mentor Graphics 2004)

x

+

x

+

A[n:0]

B[n:0] Y[(2n - 1):0]

Multiplier

Adder

Accumulator

MAC

uP

(a) One embedded core (b) Four embedded cores

uP uP

uP uP

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 41 v. 2.5, juillet 2013

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 puis-

sance 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éra-

tion, 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.

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)

Figure 3-19 – varier la fréquence d’horloge

(source : fig. 4-19, Maxfield, © Mentor Graphics 2004)

Clock signal from

outside world

Special clock

pin and pad

Daughter clocks

used to drive

internal clock trees

or output pins

ClockManager

etc.

1.0 x original clock frequency

2.0 x original clock frequency

.5 x original clock frequency

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 42 v. 2.5, juillet 2013

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 ampli-

ficateur 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.

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ées-

sorties très performants.

0o Phase shifted

90o Phase shifted

180o Phase shifted

270o Phase shifted

Clock signal from

outside world

Clock

treeFlip-flops

Special clock

pin and pad

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 43 v. 2.5, juillet 2013

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 propaga-

tion et augmenter le taux de transmission de l’information.

3.6 Comparaison d’équivalences en termes de portes logiques

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 res-

sources 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 fon-

dus, le circuit est programmé, comme montré à la Figure 3-23. L’inconvénient principal de cette techno-

logie 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.

Figure 3-22 – dispositif programmable avec fusibles

(source : fig. 2-2, Maxfield, © Mentor Graphics 2004)

a

Fat

Logic 1

y = 0 (N/A)&

Faf

b

Fbt

Fbf

Pull-up resistors

NOT

NOT

AND

Fuses

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 44 v. 2.5, juillet 2013

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 con-

nexion, il faut faire passer un courant élevé à travers l’anti-fusible pour fermer le circuit, comme montré à

la Figure 3-25.

Figure 3-24 – dispositif programmable avec anti-fusibles

(source : fig. 2-4, Maxfield, © Mentor Graphics 2004)

a

Fat

Logic 1

y = a & !b&

b

Fbf

Pull-up resistors

NOT

NOT

AND

a

Logic 1

y = 1 (N/A)&

b

Pull-up resistors

Unprogrammed

antifuses

NOT

NOT

AND

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 45 v. 2.5, juillet 2013

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 sili-

cium 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 il-

lustre un anti-fusible avant et après sa programmation.

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 im-

portant des anti-fusibles est leur immunité aux radiations, une caractéristique essentielle pour les applica-

tions 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.

a

Logic 1

y = !a & b&

b

Pull-up resistors

Programmed

antifuses

NOT

NOT

AND

(a) Before programming

Substrate

Metal

Oxide

Metal

Amorphous silicon column

(b) After programming

Polysilicon via

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 46 v. 2.5, juillet 2013

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 con-

nexion 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.

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 verti-

cale 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 électri-

quement.

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 utili-

sent des transistors spéciaux avec une grille flottante. La Figure 3-28 illustre un transistor normal et un

transistor à grille flottante.

Logic 1

Pull-up resistor

Row

(word) line

Column

(data) line

Fusible link

Transistor

Logic 0

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 47 v. 2.5, juillet 2013

En conditions normales, les deux transistors fonctionnent de façon identique et peuvent conduire le cou-

rant 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.

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 ac-

cumulé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 anti-

fusibles é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 impos-

sible 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 flot-

tante 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.

control gate

source drain

control gate

floating gate

source drain

(a) Standard MOS transistor (b) EPROM transistor

Silicon

substrate

Silicon

dioxide

Source

terminal

Control gate

terminal

Drain

terminal

Source

terminal

Control gate

terminal

Drain

terminal

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 48 v. 2.5, juillet 2013

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 techno-

logies 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 com-

porte 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 fa-

cile de programmer et d’effacer le dispositif. Dès qu’un nouveau processus de fabrication microélectro-

nique 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 applica-

tions 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.

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 49 v. 2.5, juillet 2013

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 1 à 2 générations de retard

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

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 :

)7,5,4,2(

)5,4,1,0(

)7,6,5,3,1(

)7,3,1,0(

3

2

1

0

mF

mF

mF

mF

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é.

Chapitre 3 : Technologies de logique programmable

INF3500 : Conception et réalisation de systèmes numériques 50 v. 2.5, juillet 2013

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 51 v. 2.42, décembre 2009

Chapitre 4 Flot de conception d’un circuit numérique

4.1 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 de-

sign. 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 prin-

cipes :

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 de-

vraient ê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 im-

plémenté, soit ‘en logiciel’ sur un processeur à usage général ou ‘en matériel’ sur un processeur spéciali-

sé. 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 traite-

ment (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éve-

lopper et adapter un algorithme de traitement d’image. À cette étape, il est utile de garder en tête des prin-

cipes 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 ap-

proprié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 sys-

tèmes numériques et par des recommandations pouvant aider les concepteurs dans leur tâche.

Chapitre 4 : Flot de conception d’un circuit numérique

INF3500 : Conception et réalisation de systèmes numériques 52 v. 2.5, juillet 2013

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.

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.

Figure 4-2 – description hiérarchique

(source : fig. 5-3, Maxfield, © Mentor Graphics 2004)

code HDL

schéma

diagramme

d’états

génération

de code

HDL

synthèse implémentation

génération du

fichier de

configuration

vérification par simulationannotation

des délais

Extraction statique des métriques d’implémentation

(ressources, délai, puissance)

contraintes

(temps et

espace)

vérification de la puce

puce

Graphical State Diagram

Graphical Flowchart

When clock rises If (s == 0) then y = (a & b) | c; else y = c & !(d ^ e);

Textual HDL

Top-level

block-level

schematic

Block-level schematic

Chapitre 4 : Flot de conception d’un circuit numérique

INF3500 : Conception et réalisation de systèmes numériques 53 v. 2.5, juillet 2013

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.

4.4 Simulation fonctionnelle d’un modèle VHDL

La simulation du code HDL permet au concepteur de vérifier que la description est conforme aux spécifi-

cations. Cette étape est très importante et requiert une grande proportion de l’effort de design. Un compi-

lateur 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éci-

fier plusieurs ensembles de valeurs à simuler. Différents outils de simulation facilitent la tâche de spécifi-

cation 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 inter-

connexions entre ces composantes. Le produit du synthétiseur est communément appelé « liste des inter-

connexions (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

Chapitre 4 : Flot de conception d’un circuit numérique

INF3500 : Conception et réalisation de systèmes numériques 54 v. 2.5, juillet 2013

routage typiques. Il peut y avoir une très grande variation entre cet estimé et la valeur finale après le pla-

cement 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 con-

firmer 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 compo-

santes et d’interconnexions à partir de sa spécification dans un langage de description matérielle. Le pro-

duit 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 com-

portement sous-entendu par le code et d’inférer un circuit conforme à celui-ci. En retour, le défi du con-

cepteur 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 sous-

ensemble. 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 struc-

ture 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 concep-

teur 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 compo-

santes 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 facile-

ment 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. Ce-

pendant, 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 sup-

porté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

Chapitre 4 : Flot de conception d’un circuit numérique

INF3500 : Conception et réalisation de systèmes numériques 55 v. 2.5, juillet 2013

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;

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;

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 comporte-

ment 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 con-

tiennent 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ésul-

ter 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.

D

C

B

F1

A S1

S2

D

C

B

F2

(V?)

A V?

V?

Chapitre 4 : Flot de conception d’un circuit numérique

INF3500 : Conception et réalisation de systèmes numériques 56 v. 2.5, juillet 2013

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 cor-

respondantes. Il est important de vérifier la documentation d’un outil de synthèse pour savoir quelle struc-

ture 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 effec-

tué de façon à respecter certaines contraintes de temps et/ou d’espace imposées par l’utilisateur. Le rou-

tage 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 rou-

tage 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.

Chapitre 4 : Flot de conception d’un circuit numérique

INF3500 : Conception et réalisation de systèmes numériques 57 v. 2.5, juillet 2013

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 res-

sources 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 heuris-

tiques. 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 confi-

guration 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.

Portion of gate-level netlist Contents of 3-input LUT

a b c y

00001111

00110011

01010101

01101001

aXOR

|

NOT

b

c

XNOR

|

d

e

y

Chapitre 4 : Flot de conception d’un circuit numérique

INF3500 : Conception et réalisation de systèmes numériques 58 v. 2.5, juillet 2013

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 concep-

tion 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 pro-

grammer 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 typique-

ment 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 cel-

lule 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 pla-

cer 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.

Figure 4-4 – programmer un FPGA

(source : fig. 5-3, Maxfield, © Mentor Graphics 2004)

Configuration data in

Configuration data out

= I/O pin/pad

= SRAM cell

Chapitre 4 : Flot de conception d’un circuit numérique

INF3500 : Conception et réalisation de systèmes numériques 59 v. 2.5, juillet 2013

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. Compa-

rez 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 bas-

cules, comme montré à la Figure 4-4. Montrez trois bascules ainsi reliées.

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

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

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 pro-

gramme 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 trai-

tement » (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.

Figure 5-1 – architecture générale d’un processeur

Chemin des données

Unité de contrôle

Contrôle État

Sortie des données

Sorties de contrôle

Entrée des données

Entrées de contrôle

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 62 v. 2.5, juillet 2013

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 don-

né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éra-

tions à 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 in-

dicateurs 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.

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éga-

tif. La sortie de l’unité fonctionnelle est reliée à l’entrée du bloc des registres afin de sauvegarder le résul-

tat 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 re-

gistres 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 don-

né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.

RegistresUnités fonctionnelles et

modules combinatoires

SortiesEntrées

opération état

Horloge

chargerregistres à

charger

registres à

lire

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 63 v. 2.5, juillet 2013

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éca-

lage 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.

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 64 v. 2.5, juillet 2013

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 multi-

plexeur 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:

12

0

n

k

kk DmF

où mk est un minterme formé par la kième combinaison de signaux de contrôle S. Par exemple,

l’équation booléenne d’un multiplexeur 2:1 est :

10' SDDSF

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, indi-

quant 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.

Figure 5-3 - multiplexeurs 2:1 et 4:1

0

1

F

0

D2

FD

1

D0

D3

S0

S1

1

2

3

D0

D1

S

F

D0

D1

S

F

D0

D1

S0

S1

D2

D3

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 65 v. 2.5, juillet 2013

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 équa-

tions 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 multi-

plexeur 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

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 66 v. 2.5, juillet 2013

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 0 0 0 0 0 0 0 0 0 0 1

1 0 0 1 0 0 0 0 0 0 1 0

2 0 1 0 0 0 0 0 0 1 0 0

3 0 1 1 0 0 0 0 1 0 0 0

4 1 0 0 0 0 0 1 0 0 0 0

5 1 0 1 0 0 1 0 0 0 0 0

6 1 1 0 0 1 0 0 0 0 0 0

7 1 1 1 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’) per-

met 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 com-

portementale 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.

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 67 v. 2.5, juillet 2013

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 - - - 0

0 0 0 0 0 0 0 1 0 0 0 1

0 0 0 0 0 0 1 - 0 0 1 1

0 0 0 0 0 1 - - 0 1 0 1

0 0 0 0 1 - - - 0 1 1 1

0 0 0 1 - - - - 1 0 0 1

0 0 1 - - - - - 1 0 1 1

0 1 - - - - - - 1 1 0 1

1 - - - - - - - 1 1 1 1

Tableau 5-3 – table de vérité d’un encodeur à priorité 8:3

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 68 v. 2.5, juillet 2013

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 si-

gnal 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 élec-

triquement du système.

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 69 v. 2.5, juillet 2013

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 instan-

ciation.

Figure 5-4 – registre à 4 bits à chargement parallèle

0

1D

CLK Q'

Q

clk

/

4charge

D3:D0

Q3:Q0/

4

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 70 v. 2.5, juillet 2013

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 à charge-

ment 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 effective-

ment une petite mémoire qui rassemble plusieurs des données du circuit. Il est composé de plusieurs re-

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 71 v. 2.5, juillet 2013

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.

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 con-

trô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.

D

CLK Q'

Q Q2

/

2

D

CLK Q'

Q

mode

Q3

D

CLK Q'

QD0 Q0

D

CLK Q'

QD1 Q1

entreeSerie

0

1

2

3

0

1

2

3

Q1

Q0

Q0

Q2

Q1

D2

0

1

2

3

Q1

Q3

Q2

D3

0

1

2

3

Q2

entreeSerie

Q3

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 72 v. 2.5, juillet 2013

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 connec-

ter 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.

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 73 v. 2.5, juillet 2013

Figure 5-6 – bloc des registres avec multiplexeurs

Figure 5-7 – bloc des registres avec bus et tampons à trois états

R0

D Q

charge

R1

D Q

charge

R2

D Q

charge

R3

D Q

charge

choixA

choixB

0123

charge

choixCharge

donnée

A

B

2:4

R0

D Q

charge

R1

D Q

charge

R2

D Q

chargechoixB

0123

charge

choixCharge

donnée A

B

2:4

0123

R0B

R1B

R2B

R3B

R0A

R1A

R2A

R3A

R3

D Q

charge

R0B

R1B

R2B

R3B

choixA

0123

R0A

R1A

R2A

R3A

2:4

2:4

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 74 v. 2.5, juillet 2013

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 multi-

plexeurs. D’autres sont suffisamment sophistiqués pour choisir le style le plus efficace selon la technolo-

gie 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 accom-

moder 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 énon-

cés generic. Ces paramètres sont Nreg pour le nombre de registres et Wd pour la largeur du chemin

des données en bits.

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 75 v. 2.5, juillet 2013

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 cel-

lules 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.

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 76 v. 2.5, juillet 2013

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, soustrac-

tion et multiplication et infèrent correctement des circuits combinatoires pour les implémenter. Les opéra-

teurs 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

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 77 v. 2.5, juillet 2013

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 arith-

mé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 pos-

sibles 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 pack-

ages 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é pro-

mulgué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 popu-

laires 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.

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 78 v. 2.5, juillet 2013

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

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 79 v. 2.5, juillet 2013

Les unités logiques effectuent une opération logique sur des opérandes sous le contrôle d’un signal ex-

terne. Elles sont au cœur de tout microprocesseur. Par exemple, on peut vouloir effectuer une des opéra-

tions 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 branche-

ments 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

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 80 v. 2.5, juillet 2013

compteur partagent une horloge commune. Dans un compteur à déferlement, les sorties des bascules ser-

vent 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.

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 81 v. 2.5, juillet 2013

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 :

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.

5.6 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 obte-

nez 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.

Chapitre 5 : Conception de chemins des données

INF3500 : Conception et réalisation de systèmes numériques 82 v. 2.5, juillet 2013

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 si-

mulation.

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 multi-

plication par 0, 1, 2, 3, 4, 5, 6 ou 7. N’utilisez pas l’opérateur de multiplication. Vérifiez le fonction-

nement du circuit par simulation.

14. Donnez le modèle VHDL d’un compteur à 6 bits dont la sortie est croissante et est uniquement com-

posé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 83 v. 2.42, décembre 2009

Chapitre 6 Conception d’unités de contrôle

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.

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.

circuit combinatoire

prochain état état présent

horloge

entrées sorties

éléments à

mémoire

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 84 v. 2.5, juillet 2013

La Figure 6-2 illustre un modèle général de circuit séquentiel avec des sorties de Moore et de Mealy.

Figure 6-2 – sorties de Moore et de Mealy

6.2 Analyse d’un circuit séquentiel synchrone

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 fonc-

tion 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 com-

porte 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.

circuit combinatoire

prochain état

état présent

horloge

entrées

sorties de Moore

sorties de Mealy

fonction de sortie (Moore)

fonction de sortie (Mealy)

calcul du prochain étatéléments à mémoire

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 85 v. 2.5, juillet 2013

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 si-

gnaux 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.

Figure 6-3 – exemple de circuit séquentiel

D

CLK

Q'

Q

Z

XD

CLK

Q'

Q

CLK

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 86 v. 2.5, juillet 2013

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 transi-

tions 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.

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 87 v. 2.5, juillet 2013

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 dia-

gramme 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.

État 3

Sortie: 0

État 2

Sortie: 0

État 1

Sortie: 0

État 0

Sortie: 1

-

0 0

1

-

reset

(état

initial)

1

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 88 v. 2.5, juillet 2013

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 va-

riable 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.

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 dif-

fé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émon-

tré 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

S2

Sortie = 1

S4

Sortie = 0

S3

Sortie = 0

S1

Sortie = 1

X’

X

reset

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 89 v. 2.5, juillet 2013

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 sor-

tie est remplacé par un énoncé concurrent. Cette approche offre un bon compromis entre la flexibilité

et la lisibilité du code.

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 90 v. 2.5, juillet 2013

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 entre-

pose 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 cepen-

dant 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éti-

seur utilisé afin de connaître les styles d’encodage de machines à états reconnus.

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 91 v. 2.5, juillet 2013

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 en-

tré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 satis-

faites simultanément. Ces contraintes peuvent inclure entre autres la performance, la précision, la

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 92 v. 2.5, juillet 2013

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 con-

verger 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 simpli-

fier 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 uti-

lise un style d’encodage formel comme l’un de ceux décrits à la section 6.3.4. Il est alors facile de parta-

ger 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.

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 93 v. 2.5, juillet 2013

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ésenta-

tion graphique offerte par un diagramme d’états est très avantageuse. Certains outils de conception pro-

duisent 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.

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 sous-

machines 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.

Machine

principale

Sous-

machine #1

Go1

Sous-

machine #2

Go2

Fini1

Fini2

entréessorties

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 94 v. 2.5, juillet 2013

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.

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 en-

tré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.

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.

Figure 6-9 – comparateur itératif à n bit

module

EP

SP

EC SC module

EP

SP

EC SC module

EP

SP

EC SC

EP0 EP1 Epn-1

C-1 C0 C1 Cn-2 Cn-1

SP0 SPn-1SP1

EGe

YX

EGs

comp1

Egalitecomp1

X

EGe EGs

X0

1 Y

Y0

comp1

X

EGe EGs

X1

Y

Y1

comp1

X

EGe EGs

Xn-1

Y

Yn-1

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 95 v. 2.5, juillet 2013

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 paral-

lè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éces-

site 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.

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.

YX

comp1

D

CLK

Q

CLK

set

init

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 96 v. 2.5, juillet 2013

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.

00000

0000

0000

0110

1101

011010

11010

00000

0110

1101

1001110

110100

011010

0110

1101

01001110

0000000

1001110

0110

1101

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.

0.0000

.00000

.0000

.0000

.0011

.1101

10.0110

0.01101

.1101

0.0000

.1001

.1101

110.1001

10.10011

.1101

10.0110

.1000

.1101

1110.0100

110.01001

.0000

110.1001

.0000

.1101

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).

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 97 v. 2.5, juillet 2013

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 compo-

santes 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 correspon-

dant à 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 pro-

duit 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.

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 98 v. 2.5, juillet 2013

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

multiplicande

/ W

produit

facteur

additioneur

/ W + 1

/

W

chargeFacteurchargeMultiplicande

clk

initProduit

clk clk

decaleFacteur

decaleProduit

entree /

W

facteur(0)

chargeProduit

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 99 v. 2.5, juillet 2013

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éini-

tialisation. 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.

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 pro-

cesseur. Quand ‘go’ est égal à ‘1’, la machine passe à l’état addition, dans lequel l’addition du multipli-

cande 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 si-

gnal ‘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

décalage

addition

compteur = 0reset

compteur /= 0

attente

go

compteur <= W – 1

fini <= ‘1’

compteur <=

compteur – 1

fini <= ‘0’

fini <= ‘0’

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 100 v. 2.5, juillet 2013

méfier en décrivant le processeur en VHDL afin de ne pas créer des bascules sans les désirer, ce qui affec-

terait la synchronisation de la machine.

signal de contrôle du che-

min 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

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 101 v. 2.5, juillet 2013

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 multi-

plicateur 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 pren-

dre 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, indi-

quant 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.

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 102 v. 2.5, juillet 2013

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

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 103 v. 2.5, juillet 2013

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 ‘fa-

cile’. Le code VHDL correspondant est donné à l’Exemple 6-13.

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

somme

additioneur

clk

initSomme

valeurCarte

calculeSomme

-10

moinsDix 0 1

load

reset

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 104 v. 2.5, juillet 2013

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.

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 affec-

terait 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

ajoutesomme <= somme + valeurCarte

valeurCarte = 11 : n_asfacile++

tire

tirer <= ‘1’

carteValide = ‘1’

2: somme > 16

reset

1: somme > 21 ET

n_asfacile > 0

depart

somme <= 0

n_asfacile <= 0

corrige

somme <= somme – 10

n_asfacile--

fini

3: sinon

vérifie

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 105 v. 2.5, juillet 2013

-- 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

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 106 v. 2.5, juillet 2013

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 :

XBZ

XABXB

XAYXA

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 compa-

raison?

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

Chapitre 6 : Conception d’unités de contrôle

INF3500 : Conception et réalisation de systèmes numériques 107 v. 2.5, juillet 2013

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 mo-

dule 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 ac-

tiver 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éclen-

cher la prise de mesure. Quand le bouton est pressé, une impulsion lumineuse est générée et un chro-

nomè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.

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

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

7.1 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.

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 dif-

fé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 ri-

chesse 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 con-

traintes que lors de la description d’un circuit devant être synthétisé avec des composantes logiques. On

banc d’essai

circuit à vérifier

génération de

vecteurs de

test et de

réponses

attendues

observation

des réponses

comparaison

aux réponses

attendues

vecteurs de test réponsesfichier de

stimuli et

réponses

réponses attendues

fichier des

résultats

succès/échec

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 110 v. 2.5, juillet 2013

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 fonctionne-

ment.

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 pour les vecteurs de tests

signal Cin : std_logic;

signal X : std_logic;

signal Y : 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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 111 v. 2.5, juillet 2013

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.

7.3 Simulation d’un modèle VHDL

La simulation du code HDL permet au concepteur de vérifier que la description est conforme aux spécifi-

cations. Cette étape est très importante et requiert une grande proportion de l’effort de design. Un compi-

lateur 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éne-

ments 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 utili-

sant la clause after. Il est possible que plus d’un signal change de valeur à un moment donné. Le simu-

lateur 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 abs-

trait 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 assi-

gnations de valeur à des signaux à l’intérieur du processus sont placées sur la liste des événements à trai-

ter 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

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 112 v. 2.5, juillet 2013

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 pro-

cessus. 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 proces-

sus sera relancé chaque fois qu'un des signaux dans sa liste de sensitivité subit une assignation. Les assi-

gnations 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éri-

fier, 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-

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 113 v. 2.5, juillet 2013

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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 114 v. 2.5, juillet 2013

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 con-

version 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 pa-

ramè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 264

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 pro-

cé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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 115 v. 2.5, juillet 2013

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 con-

vient 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 obser-

vé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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 116 v. 2.5, juillet 2013

[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 ac-

ceptables 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 ac-

cepte 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 conver-

sions 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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 117 v. 2.5, juillet 2013

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

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 118 v. 2.5, juillet 2013

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 pro-

babilité 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 vec-

teurs 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 simula-

tion dure plusieurs heures, si on désire obtenir des résultats progressifs, ou si on doit effectuer un traite-

ment 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 fonc-

tion 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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 119 v. 2.5, juillet 2013

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 successi-

vement 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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 120 v. 2.5, juillet 2013

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 si-

mulation, 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

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 121 v. 2.5, juillet 2013

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 fi-

chier, 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 poin-

teur 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 chan-

ger 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 compo-

sante 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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 122 v. 2.5, juillet 2013

architecture arch1a of add3bitsTB is

-- signaux pour les vecteurs de tests

signal Cin : std_logic;

signal X : std_logic;

signal Y : 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 choi-

sit 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 dif-

fé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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 123 v. 2.5, juillet 2013

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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 124 v. 2.5, juillet 2013

-- 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 ins-

tancié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 celle-

ci. 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 pou-

voir 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 sys-

tème. La complexité et le niveau de détail d’un plan de test dépendent de la taille du module, circuit, sous-

système ou système à vérifier.

Un plan de test complet pourrait entre autres détailler:

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 125 v. 2.5, juillet 2013

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éci-

fication. 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 incor-

recte 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 peu-

vent 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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 126 v. 2.5, juillet 2013

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écifica-

tions? 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 im-

possible 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 = 2

M 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 en-

semble 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 plu-

sieurs 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 permet-

tant 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 choi-

sir des données qui appartiennent à chacune des classes.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 127 v. 2.5, juillet 2013

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, respecti-

vement.

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 vec-

teurs 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.

Circuit à vérifier

Entrée1

Entrée2

Entrée3

classe 1-1

classe 1-2

classe 1-3

classe 2-1

classe 2-2

classe 3-1 classe 3-2

classe 3-3 classe 3-4

Sortie

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 128 v. 2.5, juillet 2013

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 mi-

nimale, 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 condi-

tions 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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 129 v. 2.5, juillet 2013

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 énon-

cé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. Heureuse-

ment, 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 bran-

chements.

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 com-

pléter les autres types de tests et donnent une certaine assurance au concepteur que le circuit est bien véri-

fié.

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 doi-

vent 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 va-

leurs à 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.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 130 v. 2.5, juillet 2013

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 in-

troduction 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 simpli-

fier l’effort de conception. Une hiérarchie possible peut avoir trois niveaux : le module, l’unité et le sys-

tè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 inter-

connections 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.]

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 131 v. 2.5, juillet 2013

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 cons-

tantes, 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 simula-

tion 10 ns, montrant la valeur des signaux internes et de sortie en tenant compte des délais deltas.

Chapitre 7 : Vérification de circuits numériques

INF3500 : Conception et réalisation de systèmes numériques 132 v. 2.5, juillet 2013

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 133 v. 2.42, décembre 2009

Chapitre 8 Considérations pratiques

8.1 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 con-

sidé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 pro-

blè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 à con-

cevoir, 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 va-

leur 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.

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 134 v. 2.5, juillet 2013

Une plus grande charge capacitive et une plus grande résistance des conducteurs signifient que les transis-

tors 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 compo-

sante 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 con-

traintes 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.

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 le-

quel 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.

A

B

C

F

composante

td

A

B

C

F

valeur inconnue

tdtdtd

td

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 135 v. 2.5, juillet 2013

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 pen-

dant 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.

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 mi-

nimale de son horloge, pour laquelle le circuit continue de produire des résultats corrects.

min

max

1

Tf

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 :

supropcombd ttttT min

où td est le délai de propagation de la bascule source, tcomb est le délai de propagation de la logique combi-

natoire sur le chemin, tprop est le délai de propagation sur les interconnexions, et tsu est le temps de prépa-

ration 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.

temps de

préparation tsu

temps de

maintien th

signal stable

D

CLK

Q CLK

D

Q valeur précédente valeur courante

délai de propagation Td

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 136 v. 2.5, juillet 2013

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.

Figure 8-3 – chemin critique – exemple #1

8.4 Le déphasage d’horloge

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 :

CSsupropcombd tttttT (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 :

hCSpropcombd ttttt (8-2)

Cas #3. Un déphasage d’horloge négatif est aussi possible, c'est-à-dire que la bascule source a une hor-

loge 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é.

A

D

CLK

Q

F

D

CLK

QB

D

CLK

Q

C

D

CLK

Q

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 137 v. 2.5, juillet 2013

8.5 Synchronisation entre domaines d’horloge différents

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 dispo-

sitifs 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 si-

gnaux 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. Cepen-

dant, 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 beau-

coup plus grande que la fréquence avec laquelle varie la sortie de la source asynchrone, et donc qu’on

l’échantillonne suffisamment souvent.

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ésul-

tat 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

D

CLK

Q D

CLK

Qsource

asynchronesystème synchrone

CLK

Sasync Smeta Ssync

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 138 v. 2.5, juillet 2013

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 paral-

lè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 don-

née par :

supropcombd ttttT min

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 éli-

miner 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épho-

niques. Si le délai de transmission excède un dixième de seconde, il devient perceptible et est désagréable.

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 139 v. 2.5, juillet 2013

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.

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.

Figure 8-6 – circuit plus rapide avec pipeline

1

D

CLK

Q

4

D

CLK

Q

3 ns

4 ns

4 ns

2

D

CLK

Q

3

D

CLK

Q

2 ns 5

D

CLK

Q

1

D

CLK

Q

4

D

CLK

Q

3 ns

4 ns

4 ns

2

D

CLK

Q

3

D

CLK

Q

2 ns 5

D

CLK

Q

P1

D

CLK

Q

P2

D

CLK

Q

P3

D

CLK

Q

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 140 v. 2.5, juillet 2013

8.6.4 Minimiser la latence

Certains processeurs ne traitent pas un flux important de données, mais traitent plutôt des données ponc-

tuelles à 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.

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.

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 ex-

clusives, il est de loin préférable d’utiliser un énoncé case à la place.

A

B

C

D

Somme

A

B

C

D

Somme

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 141 v. 2.5, juillet 2013

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

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 mau-

vaise décision prise à un haut niveau d’abstraction.

D1

D2

D3

D5

S

D1

D2

D3

D5

S

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 142 v. 2.5, juillet 2013

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é multivibra-

teur 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 :

N

ooutclk

kff

2_

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.

Figure 8-10 – synthétiseur numérique

mot de contrôle k

accumulateur

horloge de référence fo

/

N

ad

ditio

nneu

r

reg

istr

e bit le plus significatif:

signal d’horloge synthétisé

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 143 v. 2.5, juillet 2013

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 oscilla-

tions varie légèrement, même si en moyenne elle est égale à la période désirée.

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 144 v. 2.5, juillet 2013

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 syn-

chrone. 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 retar-

der 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 di-

zaines 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 che-

min de chaque entrée et sortie du système. Pour une entrée, le premier registre est placé dans le bloc

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 145 v. 2.5, juillet 2013

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 mo-

dules 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 bas-

cule 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 po-

sition 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 significa-

tifs et plus). Les calculatrices nous offrent cette précision, tout comme les microprocesseurs de nos sta-

tions 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 éli-

miner tout effet indésirable. Par exemple, en représentant les quantités avec 10 bits, on obtient une préci-

sion 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.

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 146 v. 2.5, juillet 2013

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 para-

mè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 res-

semblent à 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éci-

fie habituellement trois paramètres : une valeur maximale, une valeur minimale, et une valeur ty-

pique. 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 con-

nexions 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.

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 147 v. 2.5, juillet 2013

É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 :

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.

8.11 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.

2. Considérez le circuit suivant. Les bascules ont des délais de propagation de 2 ns, un temps de prépara-

tion 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.

A

D

CLK

Q

D

D

CLK

Q

3 ns

4 ns

3 ns

1 nsB

D

CLK

Q

C

D

CLK

Q

2 ns

2 nsE

D

CLK

Q

2 ns

2 ns3 ns

Chapitre 8 : Considérations pratiques

INF3500 : Conception et réalisation de systèmes numériques 148 v. 2.5, juillet 2013

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 dif-

fé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 complexi-

té de son chemin des données. Est-ce une approche valide? Dans quelle(s) circonstance(s)?

1

D

CLK

Q

3

D

CLK

Q

3 ns

2

D

CLK

Q

2 ns

4

D

CLK

Q

délaiCLK

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 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 dis-

cussion, des processeurs de type registre-registre (register-register ou load-store). Pour ce type de proces-

seur, 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 toute-

fois 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.

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 150 v. 2.5, juillet 2013

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.

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 princi-

paux. 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.

Figure 9-2 – chemin des données d’un processeur à usage général

Chemin des données

Unité de contrôle

Contrôle État

Sortie des données

Sorties de contrôle

Entrée des données

Entrées de contrôle

constante

entréeExterne

bloc des registres

A

B

choixA choixB

charge

choixCharge

donnée

clk

UAL

opération

état

A

B

F

mémoire des données

sortie

adresse

lecture/ecriture’entree

clk

registre d’étatchoixSource

sortieExterne

0123

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 151 v. 2.5, juillet 2013

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 cal-

culs 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.

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.

R0

D Q

charge

R1

D Q

charge

R2

D Q

charge

R3

D Q

charge

choixA

choixB

0123

charge

choixCharge

donnée

A

B

2:4

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 152 v. 2.5, juillet 2013

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 connec-

ter 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.

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 multi-

plexeurs. D’autres sont suffisamment sophistiqués pour choisir le style le plus efficace selon la technolo-

gie ciblée.

R0

D Q

charge

R1

D Q

charge

R2

D Q

chargechoixB

0123

charge

choixCharge

donnée A

B

2:4

0123

R0B

R1B

R2B

R3B

R0A

R1A

R2A

R3A

R3

D Q

charge

R0B

R1B

R2B

R3B

choixA

0123

R0A

R1A

R2A

R3A

2:4

2:4

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 153 v. 2.5, juillet 2013

-- 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 énon-

cé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 proces-

seurs 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écu-

tifs avant un arrondi final.

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 154 v. 2.5, juillet 2013

-- dans la partie déclarative de l’architecture

signal F : signed(Wd - 1 downto 0);

signal Z : std_logic;

signal N : std_logic;

signal op : integer range 0 to 7;

-- dans le corps de l’architecture

process(A, B, op)

begin

case op is

when 0 => F <= A + B;

when 1 => F <= A - B;

when 2 => F <= shift_right(A, 1);

when 3 => F <= shift_left(A, 1);

when 4 => F <= not(A);

when 5 => F <= A and B;

when 6 => F <= A or B;

when 7 => F <= A;

when others => F <= (others => 'X');

end case;

end process;

-- 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 re-

gistre 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.

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 155 v. 2.5, juillet 2013

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 lec-

ture 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

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 156 v. 2.5, juillet 2013

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 re-

gistre 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 instruc-

tions, un M majuscule est utilisé avec un nombre entre crochets. Le nombre indique l’adresse de la cellule

de mémoire considérée.

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 157 v. 2.5, juillet 2013

instruction

choixSource

choixCharge

charge

choixA

choixB

opération

lectureEcriture’

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

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.

9.3 L’unité de contrôle

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 che-

min 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.

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 158 v. 2.5, juillet 2013

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.

Figure 9-5 – unité de contrôle d’un processeur à usage général

Figure 9-6 – cycle des instructions de base

DQ

charge

compteur de

programme

compte

D Q

charge

registre

d’instruction

mémoire des instructions

sortie

adresse

contrôleur

etatUAL

sig

na

ux d

e c

ontr

ole

quérir

décoder

exécuter

reset depart

IR <= MI[PC]

PC <= PC + 1

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 159 v. 2.5, juillet 2013

9.3.3 Encodage des instructions en mémoire

On pourrait emmagasiner une instruction en mémoire directement en entreposant tous les signaux de con-

trô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

Rdest ← Rsource1 ◊ Rsource2 {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 - - -

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.

instruction condition bits 11-8 de

l’instruction

JUMP aucune 0000

JZ zéro 0001

JNZ pas zéro 0010

JNeg négatif 0011

JPos positif 0100

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.

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 160 v. 2.5, juillet 2013

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 don-

ner 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.

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 161 v. 2.5, juillet 2013

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 pro-

gramme 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.

quérir

décoder

écrire dans

la mémoire

UAL

registre-

registre

JUMP

STOP

lire la

mémoire

type = stop

type = JUMPtype = UAL

type = chargement de la mémoire

type = déplacement vers la mémoire

reset depart

IR <= MI[PC]

PC <= PC + 1

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 162 v. 2.5, juillet 2013

-- 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 sans condition

(IR(11 downto 8) = "0001" and Z = '1') or -- si = 0

(IR(11 downto 8) = "0010" and Z = '0') or -- si /= 0

(IR(11 downto 8) = "0011" and N = '1') or -- si < 0

(IR(11 downto 8) = "0100" and N = '0') -- si >= 0

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;

Exemple 9-6 – unité de contrôle du processeur général – machine à états

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 163 v. 2.5, juillet 2013

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 instruc-

tions, 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. Ce-

pendant, 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. Suppo-

sons 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

STOP F - - -

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 instruc-

tions à partir de leur représentation symbolique. Pour les programmes très complexes, cependant, on uti-

lise 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-

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 164 v. 2.5, juillet 2013

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 la-

tence 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 pipe-

line à 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 ins-

tructions serait alors supérieur à une instruction par cycle. On appelle ce genre de processeur un proces-

seur 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 si-

multané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 pou-

voir lire une donnée externe, de la forme Rk ← entreeExterne. Ajoutez un signal de contrôle en en-

tré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 va-

lide.

4. Considérez le processeur à usage général décrit dans ce chapitre. Ajoutez une instruction pour pou-

voir écrire une donnée externe, de la forme sortieExterne ← Rk. Ajoutez un signal de contrôle en sor-

tie, 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éci-

fié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 cel-

lules contigües à partir de l’adresse 0.

Chapitre 9 : Conception et réalisation de processeurs à usage général

INF3500 : Conception et réalisation de systèmes numériques 165 v. 2.5, juillet 2013

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?

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

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

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 expres-

sion à 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 combinai-

sons d’entrées possibles, donc si leurs tables de vérité sont identiques.

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 168 v. 2.5, juillet 2013

fonction notation

algébrique symbole table de vérité

NON

(NOT)

« inversion »

ou « complé-

ment » A

A

AF

A F

A F

0 1

1 0

ET

(AND) BA

BA

ABF

A

BF

A B F

0 0 0

0 1 0

1 0 0

1 1 1

OU

(OR) BA

BAF

A

BF

A B F

0 0 0

0 1 1

1 0 1

1 1 1

NON-OU

(NOR) BAF

A

BF

A B F

0 0 1

0 1 0

1 0 0

1 1 0

NON-ET

(NAND) ABF

A

BF

A B F

0 0 1

0 1 1

1 0 1

1 1 0

OU-exclusif

(XOR) BAF

A

BF

A B F

0 0 0

0 1 1

1 0 1

1 1 0

équivalence BAF

A

BF

A B F

0 0 1

0 1 0

1 0 0

1 1 1

Tableau 10-2 - fonctions logique de base

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 169 v. 2.5, juillet 2013

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

5. X + X' = 1 5D. X • X' = 0

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 15D. (X + Y)(Y + Z)(X' + Z) = (X + Y)(X' + Z)

10.4 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.

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 170 v. 2.5, juillet 2013

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 0 m6 = A B C’ M6 = A’ + B’ + C

7 1 1 1 m7 = A B C M7 = A’ + B’ + C’

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 va-

riables 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.

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 171 v. 2.5, juillet 2013

# A B F

0 0 0 1

1 0 1 0

2 1 0 1

3 1 1 1

# A B C F

0 0 0 0 0

1 0 0 1 1

2 0 1 0 1

3 0 1 1 1

4 1 0 0 0

5 1 0 1 0

6 1 1 0 1

7 1 1 1 0

# A B C D F

0 0 0 0 0 0

1 0 0 0 1 1

2 0 0 1 0 1

3 0 0 1 1 1

4 0 1 0 0 0

5 0 1 0 1 0

6 0 1 1 0 1

7 0 1 1 1 0

8 1 0 0 0 0

9 1 0 0 1 0

10 1 0 1 0 1

11 1 0 1 1 0

12 1 1 0 0 1

13 1 1 0 1 0

14 1 1 1 0 1

15 1 1 1 1 1

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).

1

A

B 0 1

0

1

0 2

1 3

F(A, B)

1

1

0

AB

C 00 01 11 10

0

1

0 2

1 3

6 4

7 5

F(A, B, C)

0

1

1

1

1

0

0

0

AB

CD 00 01 11 10

00

01

0 4

1 5

12 8

13 9

11

10

3 7

2 6

15 11

14 10

F(A, B, C, D)

0

0

0

1

1

0

0

0

1

1

0

1

1

1

0

1

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 172 v. 2.5, juillet 2013

Impliquant : Un groupe de forme rectangulaire de 1, 2, 4, 8, 16, 32, 64, … 2k, k N, cellules adja-

centes 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 impli-

quant 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.

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 173 v. 2.5, juillet 2013

X + Y

(OU, OR)

X

Y

XY

(ET, AND)

X

Y

X + Y

(OU-exclusif, différence,

OUX, XOR)

X

Y

X

Y

X

Y

X

Y

X X

(identité)

X

(X + Y)’

(NON-OU, NOR)

(XY)’

(NON-ET, NAND)

(X + Y)’

(coïncidence,

équivalence)

X’

(inversion, NON, NOT)

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émon-

trer des équivalences entre ces portes grâce à la logique booléenne.

X’ + YX

Y

X’ + Y’X

Y

X

Y

X

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

BABCD

CD

AB A+B+CC

AB (A+B+C)'C

AB (ABC)'C

10.7 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

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 174 v. 2.5, juillet 2013

à 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 5 ns

B

2.5 ns

FC DA

Le chronogramme suivant suppose deux signaux d’entrées A et B, et indique la valeur des signaux inter-

médiaires C et D ainsi que la sortie F en fonction du temps.

B

C

D

F

10 15 20 25 30 35 40 45 (ns)50

A

10.8 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 (2n1

) à 2n1

1.

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 175 v. 2.5, juillet 2013

base

10

base

2

base

8

base

16

0 0000 0 0

1 0001 1 1

2 0010 2 2

3 0011 3 3

4 0100 4 4

5 0101 5 5

6 0110 6 6

7 0111 7 7

8 1000 10 8

9 1001 11 9

10 1010 12 A

11 1011 13 B

12 1100 14 C

13 1101 15 D

14 1110 16 E

15 1111 17 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 carac-

tè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éo-

grammes 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.

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 176 v. 2.5, juillet 2013

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

10.9 É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 pas-

sé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

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.

S

R Q

Q' S

R Q'

Q

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 177 v. 2.5, juillet 2013

tableau caractéristique équation

S(t) R(t) Q(t) Q(t + 1)

Q’(t + 1)

mode

0 0 0 0 1 mémoire

0 0 1 1 0

0 1 0 0 1 reset

0 1 1 0 1

1 0 0 1 0 set

1 0 1 1 0

1 1 0 0 0 interdit

1 1 1 0 0

0),()()()1( SRtQtRtStQ

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.

Figure 10-3 – exemple de chronogramme d’un loquet SR

10.9.2 Loquet D

Le loquet D (Dlatch) 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 ac-

ceptables 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.

S

R

Q

Q’

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 178 v. 2.5, juillet 2013

circuit symbole

Figure 10-4 – loquet D

tableau caractéristique équation

G(t) D(t) Q(t) Q(t + 1)

mode

0 0 0 0

mémoire 0 0 1 1

0 1 0 0

0 1 1 1

1 0 0 0

transparent 1 0 1 0

1 1 0 1

1 1 1 1

)()()()()1( tDtGtQtGtQ

Figure 10-5 – tableau et équation caractéristiques du loquet D

Le chronogramme de la Figure 10-6 illustre le comportement du loquet D.

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 « trans-

parent » à un très bref instant pendant une transition du signal de contrôle. Le circuit résultant s’appelle

une bascule.

S

R Q'

QD

G

D

G Q'

Q

G

D

S

R

Q

Chapitre 10 : Annexe : Revue des systèmes numériques

INF3500 : Conception et réalisation de systèmes numériques 179 v. 2.5, juillet 2013

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 symbole

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 pro-

page à la sortie Q uniquement sur une transition positive de l’horloge.

Figure 10-8 – exemple de chronogramme d’une bascule D

D2

G2

Q2D1

G1

Q1P

D

CLK

Q

Q’

D

CLK

Q'

Q

CLK

D

G1

Q1 = P

Q2 = Q

G2

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

INF3500 : Conception et réalisation de systèmes numériques 181 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.6-

2004), 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 182 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