Documente Academic
Documente Profesional
Documente Cultură
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
5.3 Modules combinatoires utilisés dans les chemins des données .................................................. 64
7.10 Vérification d’un circuit séquentiel synchrone par banc d’essai............................................... 122
Bibliographie............................................................................................................................................. 181
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.
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.
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.
mémoire morte
Programmable Read Only Memory – PROM
Electrically Programmable ROM – EPROM
Erasable EPROM – EEPROM
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; Cin
S
S : out std_logic
);
T3
end add3bits; X T1
Y
architecture flotDeDonnees of add3bits is T2 Cout
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;
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é;
library ieee;
use ieee.std_logic_1164.all;
entity combinatoire1 is
port (
A : in std_logic; A
B : in std_logic; F
C : in std_logic; B
F : out std_logic C
);
end combinatoire1;
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.
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;
begin
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;
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;
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.
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
); D Q
end basculeD;
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;
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é.
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;
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;
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
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.
type source
catégorie valeurs
ou sous-type de la définition
boolean type prédéfini FALSE et TRUE
bit type prédéfini ‘0’ et ‘1’
256 caractères de la norme ISO 8859-1,
avec des abréviations reconnues et cer-
character type prédéfini 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
scalaires typiquement
real type prédéfini
–1.7014111E±308 à 1.7014111E±308
‘U’ : valeur inconnue, pas initialisée
‘X’ : valeur inconnue forcée
‘0’ : 0 forcé
‘1’ : 1 forcé
Package
std_logic ‘Z’ : haute impédance (pas connecté)
std_logic_1164
‘W’ : inconnu faible
‘L’ : 0 faible
‘H’ : 1 faible
‘-‘ : peu importe (don’t care)
bit_vector type prédéfini tableau de bit
string type prédéfini tableau de character
Package
std_logic_vector tableau de std_logic
std_logic_1164
composés Package tableau de std_logic, interprété
unsigned
numeric_std comme un nombre binaire non signé
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
type nom_de_mois is (janvier, février, mars, avril, mai, juin, juillet, aout,
septembre, octobre, novembre, décembre);
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.
** (exponentiation) integer
À 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;
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
end NUMERIC_STD;
end NUMERIC_STD;
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.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
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.
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.
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.
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
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.
pectives. On peut donc utiliser des diodes, ou, en pratique, des transistors. Effectivement, la combinaison
des lignes horizontales et verticales et des dispositifs de programmation implémente des portes OU tel
que montré à la Figure 3-2.
décodeur 4:16
m15
m14
m13
m12
A3 m11
m10
A2 m9
m8
A1 m7
m6
A0 m5
m4
m3
m2
m1
m0
D7 D6 D5 D4 D3 D2 D1 D0
Figure 3-3 – programmer une ROM 8 × 4 bits (source : Roth, 5e éd., fig. 9-20, © Brooks/Cole 2004)
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)
verticales correspondantes auront une valeur de ‘1’, et le premier terme aussi. Dans tous les autres cas, le
premier terme aura une valeur de ‘0’.
A3 A2 A1 A0
F2 F1 F0
programmable
PLA programmable
(un nombre limité de mintermes peuvent être générés)
fixe
programmable (un nombre limité de
PAL
(un nombre limité de mintermes peuvent être générés) mintermes peuvent être
combinés)
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.
# x y z F entrée Di valeur
z’ 0
0 0 0 0 1
D0 z’ 0 1
1 0 0 1 0 F
z 2
2 0 1 0 0
D1 0 1 3
3 0 1 1 0
4 1 0 0 0 S0
D2 z S1
5 1 0 1 1
6 1 1 0 1 x
D3 1 y
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;
H1 S1
F4
XQ
F3 D Q
Table de
conversion
F2 F CLK
16 X 1 S2
F1
S3
CLK
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.
Arrays of
programmable
logic blocks
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.
RAM blocks
Multipliers
Logic blocks
Multiplier
Adder
Accumulator
A[n:0]
xx
B[n:0] + Y[(2n - 1):0]
MAC
Figure 3-16 – multiplication-accumulation
(source : fig. 4-11, Maxfield, © Mentor Graphics 2004)
uP uP
uP
uP uP
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.
Special clock
pin and pad
0 o Phase shifted
90 o Phase shifted
Clock
Flip-flops
tree
Special clock
pin and pad
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.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.
Fuses Logic 1
Fat
a Pull-up resistors
Faf
NOT
Figure 3-22 – dispositif programmable avec fusibles
(source : fig. 2-2, Maxfield, © Mentor Graphics 2004)
Logic 1
Fat
a Pull-up resistors
b
AND
Fbf
NOT
Figure 3-23 – dispositif programmable avec fusibles fondus
(source : fig. 2-3, Maxfield, © Mentor Graphics 2004)
3.7.2 Anti-fusibles
Les anti-fusibles fonctionnent de façon contraire à un fusible. Le dispositif non programmé ne contient
que des liens qui ne sont pas encore établis, comme montré à la Figure 3-24. Pour effectuer une con-
nexion, il faut faire passer un courant élevé à travers l’anti-fusible pour fermer le circuit, comme montré à
la Figure 3-25.
Logic 1
Unprogrammed
antifuses
a Pull-up resistors
b
AND
NOT
Figure 3-24 – dispositif programmable avec anti-fusibles
(source : fig. 2-4, Maxfield, © Mentor Graphics 2004)
Logic 1
Programmed
antifuses
a Pull-up resistors
b
AND
NOT
Figure 3-25 – dispositif programmable avec anti-fusibles établis
(source : fig. 2-5, Maxfield, © Mentor Graphics 2004)
Un anti-fusible est fabriqué en plaçant du silicium amorphe entre deux conducteurs métalliques. Le 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.
Metal
Oxide
Metal
Substrate
Logic 1
Row
(word) line
Transistor Column
(data) line
Logic 0
Figure 3-27 – connexion programmable à l’aide d’un transistor
(source : fig. 2-8, Maxfield, © Mentor Graphics 2004)
On désire pouvoir établir une connexion entre une ligne horizontale et verticale. La grille du transistor est
reliée à la ligne horizontale, un terminal est relié à la ligne verticale et l’autre à la masse. La ligne 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.
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.
Source Control gate Drain Source Control gate Drain
terminal terminal terminal terminal terminal terminal
control gate
control gate
Silicon floating gate
dioxide
source drain source drain
Silicon
substrate
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.
grande :
dimension de la cellule très petite
4 ou 6 transistors
3.8 Exercices
1. Considérez un module qui doit réaliser les fonctions logiques suivantes :
F0 m(0,1,3,7)
F1 m(1,3,5,6,7)
F2 m(0,1,4,5)
F3 m(2,4,5,7)
a. Donnez son implémentation en utilisant uniquement des puces 7400 montrées à la Figure 3-1.
b. Donner son implémentation sur le circuit ROM de la Figure 3-2.
c. Donner l’implémentation des trois premières fonctions sur le PLA de la Figure 3-5.
d. Donner son implémentation sur le PAL de la Figure 3-8.
e. Donner son implémentation sur deux blocs configurables comme celui de la Figure 3-13.
2. Consultez des documents en ligne et comparez les slices de Xilinx au Logic Element d’Altera en
termes des ressources logiques disponibles et en complexité.
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?
vérification de la puce
annotation
vérification par simulation
des délais
code HDL
génération du
schéma synthèse implémentation fichier de puce
génération configuration
de code
diagramme HDL
d’états
contraintes
(temps et
espace)
Top-level
block-level
schematic
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.5 Synthèse
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.
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; D
F1
architecture demo of demoSignalVariable C
is B S2
signal S1, S2 : std_logic;
begin A S1
S1 <= A and B;
D
S2 <= S1 or C; F2
F1 <= S2 nand D; C (V?)
B V?
process(A, B, C, D)
variable V : std_logic; A V?
begin
V := A and B;
V := V or C;
V := V nand D;
F2 <= V;
end process;
end demo;
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.
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.
Configuration data in
Configuration data out
= I/O pin/pad
= SRAM cell
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.
Contrôle État
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.
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
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.
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:
2n 1
F mk Dk
k 0
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 :
F S ' D0 SD1
c’est à dire que si le signal de contrôle S vaut ‘1’, alors la sortie F est égale à l’entrée D1. Sinon, la sortie
F est égale à l’entrée D0.
Pour un multiplexeur 4:1, il y a deux signaux de contrôle S1 et S0, quatre signaux d’entrée D3, D2, D1, D0,
et un signal de sortie F. Les deux bits S1 et S0 prennent l’une de 4 combinaisons 00, 01, 10, ou 11, 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.
D0 0 D0
S
F F
D1 1 D1
S
S1 S0
D0
D0 0
D1 1
F D1
D2 2
D3 3
F
D2
S1
D3
S0
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;
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;
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
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;
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;
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
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;
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;
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;
0
D Q / Q3:Q0
D3:D0 1
/ 4
4
charge
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;
gistres de largeurs identiques qui partagent des ports d’entrée et de sortie. Le nombre de registres peut
varier de 1 seul à 1024, et leur largeur peut varier de 4 à 128 bits. Par exemple, pour un microprocesseur
de 32 ou 64 bits, le nombre réfère à la largeur des registres du bloc des registres.
Q0 0
D0 Q0
entreeSerie
1
2
D Q
Q1 3
CLK Q'
Q1 0
D1 Q1
Q0
1
2
D Q
Q2 3
CLK Q'
Q2 0
D2 Q2
Q1
1
2
D Q
Q3 3
CLK Q'
Q3 0
D3 Q3
Q2
1
2
D Q
entreeSerie 3
mode /
2 CLK Q'
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;
donnée D Q
charge
R0
charge
choixA
D Q A
2:4
R1
0
charge
choixCharge
1
2
3
D Q
R2 choixB
charge
D Q
R3
charge
R0A
donnée D Q R0B
A
charge
R0 B
charge
R1A
D Q R1B
2:4
2:4
R1 0 R0A
0
charge 1 R1A
1 choixA
choixCharge 2 R2A
2
3 R3A
3 R2A
D Q R2B
2:4
R2
0 R0B
charge
choixB
1 R1B
2 R2B
R3A
3 R3B
D Q R3B
R3
charge
Figure 5-7 – bloc des registres avec bus et tampons à trois états
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.
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;
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 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.
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.
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;
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;
end arch;
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
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;
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.
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.
entrées sorties
éléments à
mémoire
horloge
La Figure 6-2 illustre un modèle général de circuit séquentiel avec des sorties de Moore et de Mealy.
circuit combinatoire
sorties de Moore
fonction de sortie (Moore)
entrées
sorties de Mealy
fonction de sortie (Mealy)
éléments à mémoire
prochain état
calcul du prochain état
état présent
horloge
D Q
CLK
Q'
Z
X
D Q
CLK
CLK
Q'
Figure 6-3 – exemple de circuit séquentiel
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;
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;
-
reset
(état État 0 État 1
initial)
Sortie: 1 1 Sortie: 0
0 0
État 3 1 État 2
Sortie: 0 Sortie: 0
-
X’
reset S1 S3
Sortie = 1 Sortie = 0
S2 S4
Sortie = 1 Sortie = 0
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;
end troisprocessus;
Sous-
machine #1
Go1
Machine
principale
Fini1
sorties
entrées
Go2
Sous-
machine #2
Fini2
X Y
comp1
EGs
EGe
1 X Y X Y X Y Egalite
EGe comp1 EGs EGe comp1 EGs EGe comp1 EGs
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.
X Y
comp1
D Q
CLK CLK
set
init
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;
entree /
W
chargeMultiplicande chargeFacteur
decaleFacteur
multiplicande facteur
clk clk
/W
facteur(0)
additioneur
/W+1
chargeProduit
decaleProduit
produit
initProduit
clk
/
W
-- 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
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.
go
addition
fini <= ‘0’
attente
compteur <= W – 1
fini <= ‘1’
compteur /= 0
décalage
compteur = 0
compteur <=
reset compteur – 1
fini <= ‘0’
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.
-- 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';
-- signal de sortie
F <= produit(2 * W - 1 downto 0);
fini <= '1' when (etat = attente) else '0';
end arch6;
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;
moinsDix 0 1
additioneur
calculeSomme load
somme
initSomme reset
clk
Exemple 6-13 – chemin des données pour joueur de blackjack – code VHDL
depart ajoute
tire somme <= somme + valeurCarte
somme <= 0
tirer <= ‘1’
valeurCarte = 11 : n_asfacile++
n_asfacile <= 0
3: sinon
corrige
fini vérifie somme <= somme – 10
n_asfacile--
signal de contrôle
condition pour activation
du chemin des données
calculeSomme tire OU corrige
initSomme depart
moinsDix corrige
Tableau 6-2 – détails de l’unité de contrôle – blackjack
-- 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';
6.8 Exercices
1. Donner un modèle VHDL général pour une machine de Moore et un modèle VHDL général pour une
machine de Mealy, chacun utilisant deux processus.
2. Un circuit séquentiel a deux bascules dont les sorties sont A et B, deux entrées X et Y, et une sortie Z.
Donnez le diagramme d’états du circuit pour les équations d’états et de sortie suivantes :
A XY XA
B XB XA
Z XB
3. Comparez en vos propres mots les styles de description d’un circuit séquentiel décrits aux sections
6.3.1 et 6.3.2.
4. Lequel des styles décrits à la section 6.3.4 préférez-vous? Pourquoi? Quels sont les critères de 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
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.
réponses attendues
observation
génération de
des réponses
vecteurs de succès/échec
test et de
comparaison
réponses
aux réponses
attendues
attendues
fichier de vecteurs de test circuit à vérifier réponses fichier des
stimuli et
résultats
réponses
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.
library ieee;
use ieee.std_logic_1164.all;
entity add3bitsTB is
end add3bitsTB;
begin
end arch1;
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.
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.
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).
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.
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;
begin
end arch3;
library ieee;
use ieee.numeric_std.all;
use ieee.math_real.all;
begin
end arch4;
[assert expression_logique]
report message severity [note, warning, error, ou failure];
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;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity detecteurPremierTB is
end detecteurPremierTB;
begin
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
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.
-- 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.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
begin
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.
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;
begin
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;
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.
begin
end arch1a;
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
use ieee.std_logic_textio.all;
entity cctsequentielex1TB is
end cctsequentielex1TB;
begin
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;
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.
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.
classe 1-1
Entrée1
classe 1-2
classe 1-3
classe 2-1
Entrée2 Sortie
Circuit à vérifier
classe 2-2
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.
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.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; library IEEE;
use IEEE.std_logic_1164.all; use IEEE.std_logic_1164.all;
entity module1 is entity module1TB is
port ( end module1TB;
A, B : in std_logic; architecture arch of module1TB is
F : out std_logic component module1
); port (
end module1; A, B : in std_logic;
architecture arch of module1 is F : out std_logic
signal S1, S2: std_logic; );
begin end component;
S1 <= A and B; signal A,B,F : std_logic;
S2 <= not(B); begin
process (S1, S2) UUT : module1 port map (A, B, F);
begin A <= '0' after 0 ns;
F <= S1 xor S2; B <= '1' after 0 ns, '0' after 10 ns;
end process; end arch;
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.
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.
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.
A td td td
A B
composante
B F
td
C C
valeur inconnue
Figure 8-1 – délai de propagation
D Q CLK
D signal stable
délai de propagation Td
En guise d’exemple, considérons la Figure 8-3. Supposons que les bascules ont un temps de préparation
de 1 ns et un délai de propagation de 2 ns. Supposons que les portes logiques INV, ET, OU et OUX ont
des délais de propagation de 1, 2, 2 et 3 ns, respectivement. Supposons de plus qu’on peut négliger les
délais de propagation des interconnexions. Dans ce cas, le chemin critique est B – INV – OUX – OU – F
et la période minimale est 2 + 1 + 3 + 2 + 1 = 9 ns.
D Q
A D Q
D Q
CLK B
F
CLK D Q
CLK
C
CLK
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 :
td tcomb t prop tCS th (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é.
CLK CLK
CLK
Figure 8-4 – double tampon
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é.
Le désavantage principal d’une architecture avec pipeline est son coût élevé en matériel. En effet, quand
on introduit un étage de pipeline il faut synchroniser tous les signaux de cet étage, même s’ils ne sont pas
dans le chemin critique. On voit un exemple de ce fait dans la Figure 8-6 pour le signal émanant de la
bascule 3 vers la porte NON-OU. Les coûts en bascules peuvent rapidement devenir énormes. Cependant,
pour les FPGAs, la présence d’une très grande quantité de bascules prédéfinies à l’intérieur des blocs de
logique programmable rend l’utilisation d’architectures à pipeline des plus intéressantes.
D Q
1 D Q
3 ns 4
CLK 4 ns
CLK
D Q
2
CLK
D Q D Q
3 4 ns 5
2 ns
CLK CLK
D Q
D Q D Q
4 ns P2
3 2 ns 5
CLK
CLK CLK
D Q
P3
CLK
Somme
Somme
D1
D2 D1
D5
D5
D2
D3
D3
S S
accumulateur
mot de contrôle k
additionneur
horloge de référence fo
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;
-- 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;
begin
process (clkRef)
begin
if rising_edge(clkRef) then
compteur <= compteur + k;
end if;
end process;
end clockgen;
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.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.
D Q
A D Q
3 ns D
CLK 3 ns
2 ns
CLK 3 ns
D Q
1 ns
B D Q
2 ns
CLK E 2 ns
CLK
D Q
C 4 ns
CLK 2 ns
2. Considérez le circuit suivant. Les bascules ont des délais de propagation de 2 ns, un temps de pré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.
D Q
D Q
1
3 ns 3
CLK 2 ns
CLK
D Q D Q
2 4
CLK CLK
CLK
délai
3. Donnez le code VHDL pour un double tampon tel que montré à la Figure 8-4. Ce circuit peut vous
être utile dans vos laboratoires.
4. Donnez le code VHDL correspondant au circuit de la Figure 8-5, puis modifiez-le pour correspondre
au circuit de la Figure 8-6.
5. Donnez une équation exprimant le potentiel de réduction de la fréquence minimale d’horloge à l’aide
d’une architecture à pipeline, en fonction des différents délais du circuit.
6. Inspectez le rapport de synthèse d’un des circuits de vos laboratoires afin d’obtenir les délais des 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)?
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.
Contrôle État
choixSource
registre d’état
0 état
constante 1 donnée
entréeExterne 2 A A
3
adresse
choixCharge B B
mémoire des données
charge
clk
choixA choixB opération
lecture/ecriture’
entree
clk
sortieExterne
charge
R0
charge
choixA
D Q A
2:4
R1
0
charge
choixCharge
1
2
3
D Q
R2 choixB
charge
D Q
R3
charge
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.
donnée D Q R0B
A
charge
R0 B
charge
R1A
D Q R1B
2:4
2:4
R1 0 R0A
0
charge 1 R1A
1 choixA
choixCharge 2 R2A
2
3 R3A
3 R2A
D Q R2B
2:4
R2
0 R0B
charge
choixB
1 R1B
2 R2B
R3A
3 R3B
D Q R3B
R3
charge
Figure 9-4 – bloc des registres avec bus et tampons à trois états
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;
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.
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.
lectureEcriture’
choixSource
choixCharge
opération
charge
choixA
choixB
instruction
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.
Décoder l’instruction (decode). Dans cette étape, le contrôleur doit décoder l’instruction obtenue afin
de générer les signaux de contrôle pour le chemin des données.
Exécuter l’instruction (execute). Dans cette étape, le chemin des données exécute l’instruction. Cette
étape peut être décomposée en plusieurs états selon la complexité de l’instruction.
La machine à états montrée à la Figure 9-6 illustre ces étapes.
registre
d’instruction etatUAL
sortie D Q
charge
signaux de controle
mémoire des instructions
contrôleur
compteur de
programme
adresse Q D
compte
charge
reset
depart
quérir
IR <= MI[PC]
PC <= PC + 1
décoder
exécuter
bits 11-8 de
instruction condition
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.
reset
depart
quérir
IR <= MI[PC]
PC <= PC + 1
type = JUMP
type = UAL
UAL
écrire dans lire la
registre- JUMP
la mémoire mémoire
registre
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.
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.
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?
valeur équivalent
ex. : lampe ex : tension ex : alarme
logique numérique
vrai 1 allumée élevée activée
faux 0 éteinte basse désactivée
Tableau 10-1 - exemples de valeurs booléennes
notation
fonction symbole table de vérité
algébrique
NON
(NOT) F A
A F A F
« inversion » A 0 1
ou « complé- A 1 0
ment »
A B F
F AB A
ET 0 0 0
A B
F
B
(AND) 0 1 0
A B 1 0 0
1 1 1
A B F
OU F A B A
F 0 0 0
B
(OR) A B 0 1 1
1 0 1
1 1 1
A B F
A
NON-OU F 0 0 1
(NOR) F A B B
0 1 0
1 0 0
1 1 0
A B F
A
NON-ET F 0 0 1
(NAND) F AB B
0 1 1
1 0 1
1 1 0
A B F
A
OU-exclusif 0 0 0
(XOR) F A B B
F
0 1 1
1 0 1
1 1 0
A B F
A
F 0 0 1
équivalence F A B B
0 1 0
1 0 0
1 1 1
Tableau 10-2 - fonctions logique de base
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.
A F(A, B)
# A B F
B 0 1
0 0 0 1
1 0 1 0 0 1 1
2 1 0 1 0 2
3 1 1 1
1 0 1
1 3
AB F(A, B, C)
# A B C F
C 00 01 11 10
0 0 0 0 0
1 0 0 1 1
2 0 1 0 1 0 0 1 1 0
3 0 1 1 1 0 2 6 4
4 1 0 0 0
5 1 0 1 0 1 1 1 0 0
6 1 1 0 1 1 3 7 5
7 1 1 1 0
AB F(A, B, C, D)
# A B C D F
CD 00 01 11 10
0 0 0 0 0 0
1 0 0 0 1 1
2 0 0 1 0 1 00 0 0 1 0
3 0 0 1 1 1 0 4 12 8
4 0 1 0 0 0
5 0 1 0 1 0 01 1 0 0 0
6 0 1 1 0 1 1 5 13 9
7 0 1 1 1 0
8 1 0 0 0 0 11 1 0 1 0
9 1 0 0 1 0 3 7 15 11
10 1 0 1 0 1
11 1 0 1 1 0 10 1 1 1 1
12 1 1 0 0 1
2 6 14 10
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).
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.
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.
X X X X’
(identité) (inversion, NON, NOT)
X X
X+Y (X + Y)’
Y (OU, OR) Y (NON-OU, NOR)
X X
XY (XY)’
Y (ET, AND) Y (NON-ET, NAND)
X X
X+Y (X + Y)’
Y (OU-exclusif, différence, Y (coïncidence,
OUX, XOR) équivalence)
On peut aussi placer le symbole d’inversion à l’une ou aux deux entrées de la porte logique (ainsi qu’à sa
sortie). On obtient alors plusieurs combinaisons possibles, dont en voici quatre exemples. On peut démon-
trer des équivalences entre ces portes grâce à la logique booléenne.
X X
X’ + Y (X’Y)’
Y Y
X X
X’ + Y’ (X’Y’)’
Y Y
Toutes les portes logiques, sauf le NON et l’identité, peuvent avoir plus de deux entrées. En voici
quelques exemples :
A
B A
ABCD B (ABC)'
C C
D
A A
B A+B+C B (A+B+C)'
C C
A 5 ns C 2.5 ns D 5 ns
B F
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.
0 5 10 15 20 25 30 35 40 45 (ns)
code
chiffre code code code
8-4-2-1 code Gray
décimal 6-3-1-1 Excess-3 2-de-5
(BCD)
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
S Q' S Q
R Q R Q'
Figure 10-1 – loquet SR
Pour ce circuit, la sortie future Q(t + 1) dépend des valeurs des entrées présentes S(t) et R(t), ainsi que de
la valeur de la sortie présente de Q(t). Le tableau caractéristique et l’équation caractéristique du loquet SR
sont donnés à la Figure 10-2.
0 0 0 0 1
mémoire
0 0 1 1 0
0 1 0 0 1
reset Q(t 1) S (t ) R(t )Q(t ), SR 0
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
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.
Q’
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.
circuit symbole
D S Q D Q
G
R Q' G Q'
Figure 10-4 – loquet D
0 0 0 0
0 0 1 1
mémoire
0 1 0 0 Q(t 1) G(t )Q(t ) G(t ) D(t )
0 1 1 1
1 0 0 0
1 0 1 0
transparent
1 1 0 1
1 1 1 1
Figure 10-5 – tableau et équation caractéristiques du loquet D
Le chronogramme de la Figure 10-6 illustre le comportement du loquet 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). 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
P
D D1 Q1 D2 Q2 Q D Q
CLK
CLK G1 G2 Q’ Q'
CLK
G1
Q1 = P
G2
Q2 = Q