C2 — Logique et circuitsDans le dialogue d’impression, choisissez « Enregistrer au format PDF » comme destination.
Retour

Licence 1 · Architecture des ordinateurs

Cours 2Logique et circuits

Descendre du calcul au fil : poser une fonction booléenne, la simplifier, puis la construire en portes.

2 chapitres · 12 h de travail estimé

  1. 1. Algèbre de Boole6 h
  2. 2. Circuits logiques6 h

Chapitre 1 · 6 h

Algèbre de Boole

Opérateurs et tables de vérité, propriétés et théorèmes de De Morgan, formes canoniques, simplification par tableaux de Karnaugh.

En 1937, un étudiant du MIT de vingt et un ans rend un mémoire de maîtrise. Claude Shannon y remarque que l'algèbre publiée par George Boole en 1854 pour formaliser le raisonnement décrit exactement le comportement des circuits à relais des centraux téléphoniques : un relais ouvert ou fermé, une proposition fausse ou vraie, même algèbre. Le mémoire a été appelé le plus important du siècle, et il n'exagère qu'un peu — c'est lui qui autorise à calculer un circuit au lieu de le bricoler.

Ce chapitre est cette algèbre. Le chapitre 4 la câblera en portes ; ici, on apprend à poser une fonction logique, à la simplifier, et à savoir quand deux écritures différentes désignent le même circuit. La simplification n'est pas une coquetterie : chaque terme éliminé est une porte en moins, donc de la surface de silicium, de la consommation et du délai en moins.

Trois opérateurs, trois tables

Une variable booléenne ne prend que deux valeurs, 0 et 1. Trois opérateurs suffisent à tout décrire.

aabbaba \cdot b (ET)a+ba + b (OU)aˉ\bar{a} (NON)
00001
01011
10010
11110

Les notations empruntent à l'arithmétique — produit pour le ET, somme pour le OU — et le parallèle tient tant qu'on ne l'étire pas : 1+1=11 + 1 = 1 en logique, pas 2. Le OU booléen est inclusif : « l'un, l'autre, ou les deux ». Le « ou bien » exclusif du langage courant est un quatrième opérateur, le OU exclusif noté aba \oplus b, vrai quand les entrées diffèrent. On le retrouvera partout au chapitre 4 : c'est la somme de l'additionneur, et le détecteur d'égalité du comparateur.

Une fonction booléenne de nn variables associe 0 ou 1 à chacune des 2n2^n combinaisons d'entrée. Sa table de vérité est donc de taille finie, ce qui a une conséquence forte : deux expressions sont équivalentes si et seulement si elles ont la même table, et cela se vérifie exhaustivement. Aucune autre branche des mathématiques n'offre un test d'égalité aussi brutal.

Les propriétés, et les deux qui surprennent

Beaucoup de règles sont celles de l'arithmétique : commutativité, associativité, distributivité du ET sur le OU, éléments neutres (a1=aa \cdot 1 = a, a+0=aa + 0 = a) et absorbants (a0=0a \cdot 0 = 0, a+1=1a + 1 = 1).

Trois s'en écartent, et ce sont celles qui font tout le travail.

L'idempotence : a+a=aa + a = a et aa=aa \cdot a = a. Un terme répété ne compte qu'une fois.

La distributivité du OU sur le ET : a+(bc)=(a+b)(a+c)a + (b \cdot c) = (a+b) \cdot (a+c). Elle n'a aucun équivalent arithmétique — 2+(3×4)(2+3)×(2+4)2 + (3 \times 4) \neq (2+3) \times (2+4) — et c'est elle qui rend l'algèbre de Boole duale : toute identité reste vraie en échangeant simultanément ET avec OU et 0 avec 1.

L'absorption : a+(ab)=aa + (a \cdot b) = a. Si aa suffit, préciser « aa et bb » n'apporte rien. C'est la règle qui élimine le plus de termes à la main.

Restent les théorèmes de De Morgan, les plus utiles du chapitre :

ab=aˉ+bˉa+b=aˉbˉ\overline{a \cdot b} = \bar{a} + \bar{b} \qquad\qquad \overline{a + b} = \bar{a} \cdot \bar{b}

En français : la négation d'un ET est le OU des négations, et réciproquement. « Il est faux que la porte soit fermée et l'alarme active » équivaut à « la porte est ouverte ou l'alarme est inactive ». La faute classique consiste à distribuer la barre sans changer l'opérateur, et elle donne un circuit faux — pas seulement inélégant.

De Morgan a une conséquence pratique majeure, exploitée au chapitre 4 : le NON-ET (NAND) est universel. Toute fonction booléenne se construit avec des NAND seuls, et c'est pourquoi les technologies de fabrication en font leur brique de base.

Quiz · 1 question

Un système déclenche une alarme si « il est faux que le capteur A soit actif et que le capteur B soit actif ». Quelle expression est correcte ?

  • Ā · B̄ — on barre chaque variable en gardant l'opérateurbarre distribuée
  • Ā + B̄ — la négation d'un ET est le OU des négationsDe Morgan
  • A + B — la négation inverse simplement les deux variablessans négation

Réponse : C'est exactement le premier théorème de De Morgan : barre(A·B) = Ā + B̄. On le vérifie sur la table : l'expression de départ est fausse dans le seul cas A = B = 1, or Ā + B̄ n'est fausse que dans ce même cas. La première réponse est la faute classique — distribuer la barre en gardant l'opérateur — et elle donne une fonction vraie uniquement quand A = B = 0, c'est-à-dire tout autre chose. En français : « il est faux que les deux soient actifs » signifie « au moins l'un des deux est inactif », pas « les deux sont inactifs ».

Les formes canoniques

Toute fonction, si tordue soit son énoncé, s'écrit mécaniquement à partir de sa table de vérité. C'est ce qui permet de partir d'un cahier des charges en français et d'arriver à un circuit sans intuition.

La forme canonique disjonctive, dite somme de produits, se lit sur les lignes où la fonction vaut 1. Pour chacune, on écrit le produit de toutes les variables — barrées si elles valent 0 sur cette ligne — puis on fait le OU de ces produits. Chaque produit s'appelle un minterme.

Prenons la fonction « majorité » de trois variables, vraie dès que deux entrées au moins valent 1 — c'est le vote majoritaire des systèmes redondants, et la retenue sortante de l'additionneur du chapitre 4.

aabbccMMminterme
0000
0010
0100
0111aˉbc\bar{a}bc
1000
1011abˉca\bar{b}c
1101abcˉab\bar{c}
1111abcabc
M=aˉbc+abˉc+abcˉ+abcM = \bar{a}bc + a\bar{b}c + ab\bar{c} + abc

La forme conjonctive, ou produit de sommes, est la duale : elle se lit sur les lignes à 0, chaque ligne donnant une somme dont les variables sont barrées si elles valent 1. On la préfère quand la fonction est majoritairement vraie — il y a alors moins de lignes à écrire.

Ces formes ont une vertu et un défaut. La vertu : elles sont automatiques, donc jamais fausses. Le défaut : elles sont grosses. Quatre mintermes de trois variables, c'est quatre portes ET à trois entrées plus une porte OU à quatre entrées — là où la fonction majorité s'écrit en réalité ab+ac+bcab + ac + bc, trois portes ET à deux entrées.

Simplifier par tableau de Karnaugh

On peut simplifier à l'algèbre, mais c'est long et l'on ne sait jamais si l'on a fini. Le tableau de Karnaugh rend la simplification visuelle et permet de la mener jusqu'au bout.

Le tableau est une table de vérité repliée en deux dimensions, dont les en-têtes suivent un code de Gray : 00, 01, 11, 10. Ce n'est pas une coquetterie d'ordre — c'est le cœur de la méthode. Dans cet ordre, deux cases voisines ne diffèrent que par une seule variable, donc leur regroupement élimine cette variable : ab+abˉ=a(b+bˉ)=aab + a\bar{b} = a(b + \bar{b}) = a.

Voici la fonction majorité, avec aa en ligne et bcbc en colonne :

a\bca \backslash bc00011110
00010
10111

La méthode tient en quatre règles.

  1. On entoure des rectangles de 1 dont la taille est une puissance de 2 : 1, 2, 4, 8 cases. Jamais 3, jamais 6.
  2. On les prend aussi grands que possible : un groupe de 2k2^k cases élimine kk variables.
  3. Les groupes peuvent se chevaucher — l'idempotence l'autorise, a+a=aa + a = a.
  4. Le tableau est torique : les bords gauche et droit sont adjacents, de même que le haut et le bas. C'est l'oubli le plus fréquent, et il coûte systématiquement un terme.

Sur la majorité, trois groupes de deux cases suffisent : la colonne 11 donne bcbc, la paire (1,01)-(1,11) donne acac, la paire (1,11)-(1,10) donne abab. D'où :

M=ab+ac+bcM = ab + ac + bc

On est passé de quatre termes de trois variables à trois termes de deux. Il faut couvrir tous les 1 et aucun 0 ; un groupe entièrement recouvert par les autres est inutile et se retire.

Deux remarques de terrain. Le Karnaugh reste lisible jusqu'à quatre variables, tolérable à cinq, inutilisable au-delà — les outils de synthèse emploient alors des algorithmes comme Quine-McCluskey. Et lorsque certaines combinaisons d'entrée ne peuvent pas se produire, on note leur sortie « indifférente » et on s'autorise à les compter comme des 1 quand cela agrandit un groupe, comme des 0 sinon : c'est gratuit, et cela simplifie beaucoup.

Quiz · 1 question

Dans un tableau de Karnaugh à 4 variables, un étudiant obtient un groupe de 3 cases adjacentes et un autre de 4 cases, mais il n'a pas regroupé un 1 du coin haut-gauche avec un 1 du coin haut-droit. Quelles sont ses deux erreurs ?

  • Aucune : un groupe de 3 est valide, et deux coins opposés ne sont jamais adjacentsaucune erreur
  • Les groupes doivent avoir une taille en puissance de 2 (donc jamais 3), et le tableau est torique : les bords gauche et droit sont adjacentspuissance de 2 et bords adjacents
  • Les groupes ne doivent jamais se chevaucher, et il manque un groupe de 8chevauchement interdit

Réponse : Un groupe de 2^k cases élimine k variables, ce qui suppose que la taille soit une puissance de 2 : un groupe de 3 ne correspond à aucune simplification algébrique et n'est pas valide — il faut le découper en un groupe de 2 et un groupe de 2 chevauchant, ou le compléter en 4. Et le code de Gray des en-têtes rend le tableau TORIQUE : la première et la dernière colonne ne diffèrent aussi que d'une variable, elles sont donc adjacentes, comme la première et la dernière ligne. Oublier cette adjacence est l'erreur la plus fréquente et coûte un terme à chaque fois. Enfin les chevauchements sont non seulement permis mais souvent nécessaires : l'idempotence a + a = a les justifie.

À vous

L'exercice construit la table de vérité d'une expression, puis compare deux écritures. C'est l'outil qui manque le plus en TD : il transforme « je crois que c'est équivalent » en preuve, puisque l'exhaustivité sur 2n2^n lignes est un test complet.

Vous vérifierez d'abord De Morgan, puis la simplification de la fonction majorité obtenue au Karnaugh — et enfin une simplification volontairement fausse, pour voir la table diverger.

Exercice de code

Vérifiez De Morgan, puis corrigez la simplification de la fonction majorité.

Point de départ

// Une fonction booléenne de n variables est ici une fonction JS qui reçoit
// un tableau de 0/1. On énumère les 2^n entrées et on compare les sorties.

function table(f, n) {
  const lignes = [];
  for (let m = 0; m < (1 << n); m++) {
    // Bit de poids fort = première variable, pour lire comme au tableau.
    const e = [];
    for (let i = n - 1; i >= 0; i--) e.push((m >> i) & 1);
    lignes.push({ e, s: f(e) ? 1 : 0 });
  }
  return lignes;
}

function equivalentes(f, g, n, nom) {
  const tf = table(f, n), tg = table(g, n);
  const ecarts = tf.filter((l, i) => l.s !== tg[i].s);
  console.log(nom + " : " + (ecarts.length === 0 ? "équivalentes" : "DIFFÉRENTES"));
  for (const l of ecarts) {
    console.log("   contre-exemple " + l.e.join("") + " -> " +
                l.s + " contre " + tg[table(g, n).indexOf(l)]);
  }
  return ecarts.length === 0;
}

// ── De Morgan ─────────────────────────────────────────────────────────────
const gauche = ([a, b]) => !(a && b);
const droite = ([a, b]) => !a || !b;
equivalentes(gauche, droite, 2, "De Morgan  non(a.b) = na + nb");

// ── Majorité : forme canonique contre forme simplifiée ────────────────────
// Vraie dès que deux entrées au moins valent 1.
const canonique = ([a, b, c]) =>
  (!a && b && c) || (a && !b && c) || (a && b && !c) || (a && b && c);

const simplifiee = ([a, b, c]) => (a && b) || (a && c);   // ← il manque un terme

equivalentes(canonique, simplifiee, 3, "Majorité");

// ── À VOUS ────────────────────────────────────────────────────────────────
// 1. Le Karnaugh donnait ab + ac + bc. Corrigez simplifiee et relancez.
// 2. Écrivez le OU exclusif a XOR b de deux façons — (a et non b) ou
//    (non a et b), puis a différent de b — et vérifiez leur équivalence.

Solution

function table(f, n) {
  const lignes = [];
  for (let m = 0; m < (1 << n); m++) {
    const e = [];
    for (let i = n - 1; i >= 0; i--) e.push((m >> i) & 1);
    lignes.push({ e, s: f(e) ? 1 : 0 });
  }
  return lignes;
}

function equivalentes(f, g, n, nom) {
  const tf = table(f, n), tg = table(g, n);
  const ecarts = [];
  for (let i = 0; i < tf.length; i++) {
    if (tf[i].s !== tg[i].s) ecarts.push({ e: tf[i].e, f: tf[i].s, g: tg[i].s });
  }
  console.log(nom + " : " + (ecarts.length === 0 ? "équivalentes" : "DIFFÉRENTES"));
  for (const x of ecarts) {
    console.log("   contre-exemple " + x.e.join("") + " -> " + x.f + " contre " + x.g);
  }
  return ecarts.length === 0;
}

const gauche = ([a, b]) => !(a && b);
const droite = ([a, b]) => !a || !b;
equivalentes(gauche, droite, 2, "De Morgan  non(a.b) = na + nb");

const canonique = ([a, b, c]) =>
  (!a && b && c) || (a && !b && c) || (a && b && !c) || (a && b && c);

// Les trois groupes de deux cases lus au Karnaugh : ab, ac et bc. Le terme
// bc est celui que l'oubli de la colonne 11 fait sauter.
const simplifiee = ([a, b, c]) => (a && b) || (a && c) || (b && c);

equivalentes(canonique, simplifiee, 3, "Majorité");

// Le OU exclusif, deux écritures.
const xorPortes = ([a, b]) => (a && !b) || (!a && b);
const xorDiff = ([a, b]) => a !== b;
equivalentes(xorPortes, xorDiff, 2, "XOR");

En travaux pratiques

Travaux pratiques 3 · 3 h

Simplifier avant de câbler

Passer d'un énoncé en français à une expression booléenne, la simplifier, et prouver que la simplification n'a rien changé — parce qu'au TP suivant, chaque terme coûtera une porte.

Avant de commencer

  • Le TP 1 pour la notation binaire
  • De quoi écrire un petit programme, pour la vérification exhaustive

Énoncé

  1. De l'énoncé à la tableUn vote à trois : la sortie vaut 1 si au moins deux entrées valent 1. Écrivez la table de vérité complète, huit lignes.
  2. La forme canoniqueÉcrivez la somme des mintermes, un terme par ligne à 1. Comptez le nombre de portes ET, OU et NON qu'elle exigerait.
  3. SimplifierSimplifiez par tableau de Karnaugh, puis vérifiez algébriquement en repartant de la forme canonique. Recomptez les portes. Indice : Les regroupements sont des paires de cases adjacentes valant 1, et un terme peut servir dans plusieurs regroupements.
  4. Prouver l'équivalenceÉcrivez un programme qui parcourt les huit combinaisons et compare les deux expressions ligne à ligne. C'est la seule preuve que votre simplification est juste.
  5. Tout en NON-ETRéécrivez l'expression simplifiée en n'utilisant que des portes NON-ET, avec De Morgan. Vérifiez à nouveau par le programme.
  6. Une fonction utileMême démarche complète pour le comparateur d'égalité de deux nombres de 2 bits. Vous vous en resservirez au TP 4.
  7. Le piège de la simplificationSimplifiez A·B + A·NON(B) + NON(A)·B en gardant le compte des portes, puis dites lequel des deux résultats vous câbleriez si les entrées arrivaient à des instants différents.

C'est réussi quand

  • Votre programme confirme l'équivalence sur les huit lignes, sans exception
  • Vous passez de 3 portes ET à 3 portes ET… mais de 3 entrées à 2 entrées chacune
  • Vous savez énoncer De Morgan sans le relire

Correction

Table de vérité et forme canonique
A B C | S            S = A'BC + AB'C + ABC' + ABC
0 0 0 | 0
0 0 1 | 0            4 termes de 3 littéraux
0 1 0 | 0            → 4 portes ET à 3 entrées
0 1 1 | 1            → 1 porte OU à 4 entrées
1 0 0 | 0            → 3 portes NON
1 0 1 | 1
1 1 0 | 1
1 1 1 | 1

La forme canonique s'obtient mécaniquement, sans réfléchir : une ligne à 1, un terme. C'est sa qualité — on ne peut pas se tromper — et son défaut : elle est toujours la plus coûteuse.

La simplification, et sa vérification algébrique
S = A'BC + AB'C + ABC' + ABC

on duplique ABC (car X + X = X) :
S = (A'BC + ABC) + (AB'C + ABC) + (ABC' + ABC)
= BC(A' + A) + AC(B' + B) + AB(C' + C)
= BC + AC + AB

3 portes ET à 2 entrées, 1 porte OU à 3 entrées, 0 porte NON

Dupliquer un terme pour pouvoir factoriser trois fois est le geste qui surprend, et il est parfaitement licite : en booléen, X + X = X. Le gain n'est pas dans le nombre de portes ET mais dans leur TAILLE — deux entrées au lieu de trois — et dans la disparition des trois inverseurs. Sur un circuit réel, moins d'entrées signifie moins de transistors et un chemin plus court.

La vérification exhaustiveverifier.c
for (int a = 0; a < 2; a++)
for (int b = 0; b < 2; b++)
  for (int c = 0; c < 2; c++) {
    int canonique = (!a&&b&&c) || (a&&!b&&c) || (a&&b&&!c) || (a&&b&&c);
    int simplifie = (b&&c) || (a&&c) || (a&&b);
    if (canonique != simplifie)
        printf("DIFFÉRENCE en %d%d%d\n", a, b, c);
  }

Huit lignes seulement : l'exhaustif est ici possible, et c'est un luxe. Dès qu'on dépasse une vingtaine de variables il ne l'est plus, et il faut un vérificateur formel. Mais tant qu'il est possible, il est la meilleure preuve qui soit — supérieure à une relecture.

Tout en NON-ET
X + Y = (X' · Y')'      (De Morgan)
X · Y = ((X · Y)')'      (double négation)
X'    = (X · X)'         (une NON-ET à entrées reliées)

S = BC + AC + AB
= ( (BC)' · (AC)' · (AB)' )'
→ 3 NON-ET pour les produits, 1 NON-ET à 3 entrées pour la somme

La NON-ET est universelle : elle suffit à tout construire. Ce n'est pas une curiosité théorique — une usine qui ne fabrique qu'un seul type de porte simplifie sa production, et en technologie CMOS la NON-ET demande moins de transistors que la ET, qui est une NON-ET suivie d'un inverseur.

Le piège : simplifier n'est pas toujours améliorer
A·B + A·B' + A'·B  =  A + B    (2 portes → 1 porte)

mais si A et B n'arrivent pas au même instant, la forme simplifiée
peut produire une impulsion parasite pendant la transition —
un ALÉA que la forme redondante n'avait pas.

En combinatoire pure, sortie stable après stabilisation des entrées, la forme simplifiée gagne toujours. Dès qu'un signal est lu pendant la transition, on RAJOUTE volontairement des termes redondants pour supprimer l'aléa. C'est aussi pour cela que le TP 4 synchronisera tout sur une horloge : on n'observe les sorties qu'une fois qu'elles sont stables.

Ce que la suite en fait

Chaque objet de ce chapitre a un équivalent matériel immédiat, et le chapitre 4 ne fera guère que traduire. Une expression devient un assemblage de portes ; une somme de produits devient deux étages de portes ; De Morgan devient la possibilité de tout construire en NAND ; et le nombre de termes après Karnaugh devient un nombre de transistors.

La fonction majorité étudiée ici n'a rien d'un exemple gratuit : c'est exactement la retenue sortante de l'additionneur complet. Vous l'avez déjà simplifiée, il ne restera qu'à la câbler.

À retenir

Flashcards · 4 cartes

Énoncez les deux théorèmes de De Morgan, et quelle faute classique guette.
barre(a·b) = ā + b̄ et barre(a+b) = ā · b̄ : la négation d'un ET est le OU des négations, et réciproquement. La faute classique est de distribuer la barre en GARDANT l'opérateur (écrire ā · b̄ pour barre(a·b)), ce qui donne une fonction complètement différente. Conséquence pratique : le NAND est universel, toute fonction se câble en NAND seuls.
Comment lit-on la forme canonique somme de produits sur une table de vérité ?
On ne regarde que les lignes où la fonction vaut 1. Pour chacune, on écrit le produit de TOUTES les variables, barrées si elles valent 0 sur cette ligne — c'est un minterme — puis on fait le OU de ces produits. La méthode est automatique donc jamais fausse, mais elle produit une expression grosse, qu'il faut ensuite simplifier.
Pourquoi les en-têtes d'un tableau de Karnaugh suivent-ils l'ordre 00, 01, 11, 10 ?
C'est un code de Gray : deux cases voisines ne diffèrent que d'UNE variable. Leur regroupement élimine donc cette variable, puisque ab + ab̄ = a. Sans cet ordre, l'adjacence géométrique ne correspondrait à aucune simplification algébrique et la méthode ne fonctionnerait pas.
Quelles sont les quatre règles de regroupement dans un Karnaugh ?
1) Les groupes ont une taille en puissance de 2 (1, 2, 4, 8) — jamais 3. 2) On les prend aussi grands que possible : 2^k cases éliminent k variables. 3) Ils peuvent se chevaucher, l'idempotence a + a = a l'autorise. 4) Le tableau est torique : bords gauche/droit et haut/bas sont adjacents — l'oubli le plus fréquent. Il faut couvrir tous les 1 et aucun 0.

Chapitre 2 · 6 h

Circuits logiques

Portes logiques ; additionneur, multiplexeur, décodeur et comparateur ; bascules, registres et compteurs.

Un processeur récent compte des dizaines de milliards de transistors. Ce nombre décourage, et il ne devrait pas : la variété des briques, elle, tient sur une page. Quelques portes logiques, un additionneur, un multiplexeur, un décodeur, une bascule — et tout le reste est de la répétition et de l'assemblage.

Ce chapitre est la charnière du cours. Le chapitre 3 a donné l'algèbre ; on la câble ici. Le chapitre 5 posera l'architecture du processeur ; ses unités seront faites de ce qu'on construit maintenant. Et le TP prend tout son sens ici : monter un additionneur porte par porte dans Logisim, puis écrire la même addition en assembleur au chapitre 6, est ce qui relie concrètement les deux moitiés du semestre.

Les portes, et la seule qui compte vraiment

Une porte logique est un circuit qui réalise un opérateur booléen. Les trois de base — ET, OU, NON — se complètent de trois formes niées, NAND, NOR et XOR, plus utiles en pratique que leurs cousines directes.

PorteSortie à 1 quand…Notation
ET (AND)toutes les entrées valent 1aba \cdot b
OU (OR)au moins une entrée vaut 1a+ba + b
NON (NOT)l'entrée vaut 0aˉ\bar{a}
NON-ET (NAND)pas toutes les entrées à 1ab\overline{a \cdot b}
NON-OU (NOR)aucune entrée à 1a+b\overline{a + b}
OU exclusif (XOR)les entrées diffèrentaba \oplus b

Le fait remarquable du chapitre est que le NAND est universel : on construit toute fonction booléenne avec des NAND seuls. La démonstration tient en trois lignes, et De Morgan en est la clé.

NON a    = NAND(a, a)a ET b   = NON( NAND(a, b) )        = NAND( NAND(a,b), NAND(a,b) )a OU b   = NAND( NON a, NON b )     par De Morgan

Ce n'est pas une curiosité théorique. En technologie CMOS, la porte naturelle est justement inverseuse : un NAND coûte quatre transistors, un ET en coûte six — un NAND suivi d'un inverseur. Les bibliothèques de cellules sont donc bâties sur NAND et NOR, et une conception qui les ignore paie ses portes plus cher qu'il ne faut.

Combinatoire : la sortie ne dépend que des entrées

Un circuit est combinatoire quand sa sortie est entièrement déterminée par ses entrées courantes. Pas de mémoire, pas d'histoire : mêmes entrées, même sortie, toujours.

Le demi-additionneur, puis l'additionneur complet

Additionner deux bits produit une somme et une retenue. La table est celle du chapitre 1 :

aabbssrr
0000
0110
1010
1101

La colonne somme vaut 1 quand les entrées diffèrent : c'est un XOR. La colonne retenue vaut 1 quand les deux valent 1 : c'est un ET. Deux portes, et voilà le demi-additionneur — ainsi nommé parce qu'il lui manque l'essentiel : il ne sait pas recevoir la retenue de la colonne précédente.

L'additionneur complet prend trois entrées, aa, bb et la retenue entrante rer_e :

s=abrers=ab+are+bres = a \oplus b \oplus r_e \qquad\qquad r_s = ab + a r_e + b r_e

Regardez la seconde expression : c'est exactement la fonction majorité simplifiée au Karnaugh du chapitre 3. Il y a une retenue sortante dès que deux des trois entrées valent 1, ce qui est intuitif — additionner trois bits donne 2 ou 3 dès que deux d'entre eux sont à 1.

De un bit à nn : l'additionneur à propagation

Pour additionner deux mots de 8 bits, on chaîne huit additionneurs complets, la retenue sortante de chacun alimentant la retenue entrante du suivant. C'est l'additionneur à propagation de retenue (ripple-carry), et c'est le circuit du TP.

Il a un défaut, et ce défaut gouverne toute l'architecture qui suit : la retenue doit traverser les huit étages avant que le dernier bit soit correct. Le temps de calcul est proportionnel au nombre de bits. Sur 64 bits, c'est intenable — d'où les additionneurs à anticipation de retenue, qui calculent les retenues en parallèle, plus rapides et plus gourmands en portes. C'est le premier compromis surface/vitesse du cours, et il ne sera pas le dernier.

Et la soustraction ? Le chapitre 2 a déjà répondu : ab=a+(b)a - b = a + (-b), et b-b s'obtient en inversant les bits de bb puis en ajoutant 1. Concrètement, on place un XOR sur chaque bit de bb commandé par un signal MM, et on injecte ce même MM comme retenue entrante du premier étage. M=0M = 0 : le circuit additionne. M=1M = 1 : il soustrait. Le même additionneur fait les deux, pour le prix de huit portes XOR — c'est là que le choix du complément à deux se paie en silicium économisé.

Multiplexeur, décodeur, comparateur

Trois autres briques reviennent partout.

Le multiplexeur est un aiguillage : 2k2^k entrées de données, kk entrées de commande, une sortie qui recopie l'entrée désignée. Le plus simple, à deux entrées, s'écrit s=cˉe0+ce1s = \bar{c}\,e_0 + c\,e_1. C'est le composant qui, au chapitre 5, choisira si l'unité de calcul reçoit un registre ou une valeur immédiate.

Le décodeur fait l'inverse : kk entrées, 2k2^k sorties, et une seule sortie active, celle dont le numéro est écrit en binaire sur les entrées. C'est ainsi qu'une adresse sélectionne une case mémoire, et qu'un code d'opération active la bonne commande.

Le comparateur teste l'égalité de deux mots. Deux bits sont égaux quand leur XOR vaut 0 ; deux mots sont égaux quand tous leurs XOR valent 0, ce qui s'écrit avec un NOR final. La comparaison d'ordre demande davantage de logique, et se ramène souvent à une soustraction dont on lit le signe — encore le même additionneur.

Quiz · 1 question

Pourquoi une machine n'a-t-elle pas besoin d'un circuit de soustraction distinct de son additionneur ?

  • Parce que la soustraction binaire posée est identique à l'addition, avec des emprunts au lieu de retenuescircuit symétrique
  • Parce qu'en complément à deux, a − b = a + (−b) : il suffit d'inverser les bits de b avec des XOR commandés et d'injecter 1 comme retenue entrantecomplément à deux
  • Parce que le processeur convertit d'abord les nombres en décimal, où la soustraction est directeconversion

Réponse : C'est le bénéfice concret du complément à deux vu au chapitre 2. Inverser les bits de b puis ajouter 1 donne −b ; or l'addition de 1 est gratuite ici, puisque l'additionneur possède déjà une retenue entrante sur son premier étage. On place donc un XOR par bit de b, commandé par un signal M, et on branche ce même M sur la retenue entrante : M = 0 additionne, M = 1 soustrait. Coût total pour un additionneur 8 bits : huit portes XOR. Un circuit de soustraction séparé coûterait autant que l'additionneur lui-même.

Séquentiel : quand le circuit se souvient

Tout ce qui précède oublie instantanément. Or un processeur doit retenir : le contenu d'un registre, la valeur d'un compteur, l'adresse de la prochaine instruction. Il faut un circuit dont la sortie dépende aussi de son état passé. On l'obtient par un moyen simple et troublant : reboucler une sortie sur une entrée.

La bascule RS est le cas fondateur : deux portes NOR croisées, chacune recevant la sortie de l'autre. Trois comportements. Mettre SS (set) à 1 force la sortie à 1. Mettre RR (reset) à 1 la force à 0. Et laisser les deux à 0 conserve l'état — c'est là qu'il y a mémoire, dans le simple fait que la boucle s'auto-entretient. La combinaison R=S=1R = S = 1 est interdite : elle produit un état incohérent, et l'issue dépend de qui retombe à 0 en premier.

Une bascule RS réagit dès que ses entrées bougent, ce qui est ingérable dans un circuit complexe. On la discipline avec une horloge, signal carré qui rythme tout le système, et l'on obtient la bascule D : une entrée de donnée, une entrée d'horloge, et la sortie qui recopie l'entrée au moment décidé par l'horloge.

Ce moment fait toute la différence. Une bascule sur niveau (latch) est transparente tant que l'horloge est haute : la sortie suit l'entrée, ce qui peut faire traverser plusieurs étages en un seul cycle. Une bascule sur front ne prend en compte l'entrée qu'à l'instant précis où l'horloge monte, puis se verrouille. C'est celle qu'on emploie partout, parce qu'elle rend le circuit prévisible : à chaque front, tout l'état bascule d'un coup vers sa valeur suivante, et ce qui se passe entre deux fronts n'a aucune importance.

D'où la contrainte qui fixe la fréquence d'une machine, et que le chapitre 5 reprendra : entre deux fronts, il faut que le plus long chemin combinatoire — le chemin critique, la propagation de la retenue par exemple — ait eu le temps de se stabiliser. La période d'horloge est dictée par le circuit le plus lent, pas par le plus rapide.

Registres et compteurs

À partir de la bascule D, deux assemblages suffisent.

Un registre de nn bits est un paquet de nn bascules D partageant la même horloge et le même signal d'écriture. Tous les bits basculent ensemble, ce qui est indispensable : un registre dont les bits changeraient à des instants différents laisserait lire des valeurs qui n'ont jamais existé. Un registre à décalage relie en plus la sortie de chaque bascule à l'entrée de la suivante, et décale son contenu d'un rang à chaque front — c'est le décalage qui multiplie ou divise par deux du chapitre 1, réalisé en fils plutôt qu'en calcul.

Un compteur est un registre bouclé sur un incrémenteur : à chaque front, il ajoute 1 à son propre contenu. Sur nn bits, il compte modulo 2n2^n et revient à zéro — le tour de compteur du chapitre 2, sous sa forme matérielle. C'est directement le compteur ordinal du chapitre 5, celui qui contient l'adresse de la prochaine instruction et qui s'incrémente à chaque cycle.

Quiz · 1 question

Qu'est-ce qui distingue fondamentalement un circuit séquentiel d'un circuit combinatoire, et par quel moyen l'obtient-on ?

  • Le séquentiel utilise des portes plus complexes, capables de retenir une valeurportes spéciales
  • Le séquentiel reboucle une sortie sur une entrée : sa sortie dépend alors de son état passé, pas seulement des entrées courantesrebouclage
  • Le séquentiel est simplement plus lent, car il traite les entrées les unes après les autresvitesse

Réponse : Il n'existe pas de porte « à mémoire » : la mémoire naît de la TOPOLOGIE, pas du composant. Deux portes NOR ordinaires, chacune recevant la sortie de l'autre, forment une bascule RS dont l'état se conserve quand les deux entrées retombent à 0 — la boucle s'auto-entretient. C'est le seul mécanisme, et tout le reste (bascule D, registre, compteur, mémoire vive) en dérive. La discipline par une horloge sur FRONT vient ensuite : elle rend le circuit prévisible en faisant basculer tout l'état au même instant.

À vous

L'exercice construit l'additionneur du TP, mais en JavaScript et à partir des portes seules : un additionneur complet, puis huit en cascade, puis l'astuce du XOR commandé qui transforme l'additionneur en soustracteur.

Le jeu de tests reprend volontairement les cas du chapitre 2 — 100+50100 + 50 et 128-128 — pour que le circuit reproduise, à la porte près, les débordements que le codage annonçait.

Exercice de code

Câblez la retenue de l'additionneur complet, puis faites-en un soustracteur.

Point de départ

// Les portes. On ne s'autorise rien d'autre : pas de +, pas de -.
const NON = (a) => a ^ 1;
const ET  = (a, b) => a & b;
const OU  = (a, b) => a | b;
const XOR = (a, b) => a ^ b;

// Additionneur complet : trois bits en entrée, somme et retenue en sortie.
function additionneurComplet(a, b, re) {
  const s = XOR(XOR(a, b), re);
  const rs = 0;              // ← à écrire : la fonction majorité de a, b, re
  return { s, rs };
}

const N = 8;
const versBits = (n) => Array.from({ length: N }, (_, i) => (n >> i) & 1); // [poids faible…]
const versNombre = (bits) => bits.reduce((n, b, i) => n + b * (1 << i), 0);

// Additionneur n bits à propagation de retenue, avec entrée de commande M.
// M = 0 : calcule a + b.  M = 1 : doit calculer a − b.
function additionner(a, b, M) {
  const A = versBits(a), B = versBits(b);
  const S = [];
  let retenue = 0;           // ← que doit valoir la retenue entrante si M = 1 ?
  for (let i = 0; i < N; i++) {
    const bi = B[i];         // ← et que doit devenir ce bit si M = 1 ?
    const { s, rs } = additionneurComplet(A[i], bi, retenue);
    S.push(s);
    retenue = rs;
  }
  return { motif: versNombre(S), retenueSortante: retenue };
}

// ── À VOUS ────────────────────────────────────────────────────────────────
// 1. Écrivez rs dans additionneurComplet (majorité : ab + a·re + b·re).
// 2. Faites soustraire le circuit : inverser chaque bit de B par un XOR
//    commandé par M, et injecter M comme retenue entrante initiale.

const signe = (m) => (m >= 128 ? m - 256 : m);
const CAS = [
  { a: 11,  b: 7,   M: 0 },
  { a: 100, b: 50,  M: 0 },
  { a: 5,   b: 5,   M: 1 },
  { a: 3,   b: 10,  M: 1 },
  { a: 255, b: 1,   M: 0 },
];

for (const c of CAS) {
  const r = additionner(c.a, c.b, c.M);
  const attendu = c.M === 0 ? c.a + c.b : c.a - c.b;
  const lu = signe(r.motif);
  const ok = lu === attendu || r.motif === (attendu & 255) ? "  ok" : "  X";
  console.log(
    (c.a + (c.M ? " - " : " + ") + c.b).padEnd(12) +
    "motif " + r.motif.toString(2).padStart(8, "0") +
    "  non signé " + String(r.motif).padStart(3) +
    "  signé " + String(lu).padStart(4) + ok
  );
}

Solution

const NON = (a) => a ^ 1;
const ET  = (a, b) => a & b;
const OU  = (a, b) => a | b;
const XOR = (a, b) => a ^ b;

function additionneurComplet(a, b, re) {
  const s = XOR(XOR(a, b), re);
  // La retenue sortante est la fonction majorité des trois entrées : il y a
  // report dès que deux d'entre elles valent 1. C'est l'expression obtenue
  // au tableau de Karnaugh du chapitre 3.
  const rs = OU(OU(ET(a, b), ET(a, re)), ET(b, re));
  return { s, rs };
}

const N = 8;
const versBits = (n) => Array.from({ length: N }, (_, i) => (n >> i) & 1);
const versNombre = (bits) => bits.reduce((n, b, i) => n + b * (1 << i), 0);

function additionner(a, b, M) {
  const A = versBits(a), B = versBits(b);
  const S = [];
  // M sert deux fois : il inverse B et il fournit le « + 1 » du complément
  // à deux, gratuitement, par la retenue entrante du premier étage.
  let retenue = M;
  for (let i = 0; i < N; i++) {
    const bi = XOR(B[i], M);
    const { s, rs } = additionneurComplet(A[i], bi, retenue);
    S.push(s);
    retenue = rs;
  }
  return { motif: versNombre(S), retenueSortante: retenue };
}

const signe = (m) => (m >= 128 ? m - 256 : m);
const CAS = [
  { a: 11,  b: 7,   M: 0 },
  { a: 100, b: 50,  M: 0 },
  { a: 5,   b: 5,   M: 1 },
  { a: 3,   b: 10,  M: 1 },
  { a: 255, b: 1,   M: 0 },
];

for (const c of CAS) {
  const r = additionner(c.a, c.b, c.M);
  const attendu = c.M === 0 ? c.a + c.b : c.a - c.b;
  const lu = signe(r.motif);
  const ok = lu === attendu || r.motif === (attendu & 255) ? "  ok" : "  X";
  console.log(
    (c.a + (c.M ? " - " : " + ") + c.b).padEnd(12) +
    "motif " + r.motif.toString(2).padStart(8, "0") +
    "  non signé " + String(r.motif).padStart(3) +
    "  signé " + String(lu).padStart(4) + ok
  );
}

// 100 + 50 : le motif tient sur 8 bits, aucune retenue ne sort, et pourtant
// la lecture signée donne −106. 255 + 1 : la retenue sort, et le motif
// retombe à 0. Deux débordements de natures différentes, comme au ch. 2.

En travaux pratiques

Travaux pratiques 4 · 4 h

Construire une unité arithmétique et logique

Assembler, porte par porte, le circuit qui calcule dans un processeur — puis lui ajouter la mémoire d'un bit, qui fait basculer du combinatoire au séquentiel.

Avant de commencer

  • Le TP 3 : simplification et vérification exhaustive
  • Un simulateur de circuits logiques : Logisim Evolution, Digital, ou équivalent
  • Le complément à deux du TP 2

Énoncé

  1. Le demi-additionneurConstruisez le circuit qui additionne deux bits et produit une somme et une retenue. Deux portes suffisent. Vérifiez les quatre cas.
  2. L'additionneur completAjoutez une retenue entrante. Établissez d'abord la table de vérité à trois entrées, simplifiez comme au TP 3, puis câblez. Vérifiez les huit cas. Indice : La somme est un XOR à trois entrées ; la retenue sortante est la fonction majorité du TP 3 — vous l'avez déjà simplifiée.
  3. Quatre bitsChaînez quatre additionneurs complets. Testez 7 + 5, puis 15 + 1. Comptez ensuite le nombre de portes traversées par le signal entre l'entrée et le bit de poids fort.
  4. Soustraire sans circuit de soustractionAjoutez une entrée de commande qui, à 1, fait calculer A − B. Un XOR par bit de B et la retenue initiale suffisent. Testez 7 − 5 puis 5 − 7. Indice : Relisez le TP 2 : −B, c'est B inversé plus un.
  5. Les drapeauxAjoutez la sortie Z (résultat nul) et la sortie V (débordement signé). Trouvez le cas où V doit valoir 1 alors que la retenue sortante vaut 0.
  6. L'unité complèteAjoutez un multiplexeur commandé par deux bits, qui choisit entre ET, OU, addition et soustraction. Vous avez une UAL 4 bits.
  7. Une mémoire d'un bitConstruisez une bascule D, reliez-en quatre à une horloge, et faites-en un registre. Chargez le résultat de l'UAL dedans, puis réinjectez-le en entrée A.
  8. Le compteurCâblez le registre pour qu'il s'incrémente à chaque coup d'horloge. Vous venez de construire un compteur ordinal — celui du chapitre suivant.

C'est réussi quand

  • 15 + 1 donne 0 avec la retenue sortante à 1
  • 7 − 5 donne 2 sans qu'aucun circuit de soustraction n'existe dans votre schéma
  • Votre compteur avance d'exactement un par front d'horloge
  • Vous savez dire quelle sortie s'allume sur 7 + 1 en signé, et pourquoi

Correction

Demi puis additionneur complet
demi-additionneur          additionneur complet
S = A XOR B                S = A XOR B XOR Cin
C = A ET  B                Cout = (A ET B) + (A ET Cin) + (B ET Cin)
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                la fonction MAJORITÉ du TP 3

La retenue sortante vaut 1 dès qu'au moins deux des trois entrées valent 1 — c'est littéralement le vote à trois que vous aviez simplifié. Un exercice qui semblait abstrait était en fait la moitié d'un additionneur.

Quatre bits, et le prix du chaînage
15 + 1 :  1111 + 0001 = 0000, Cout = 1

profondeur : le bit de poids fort attend la retenue du rang 2,
qui attend celle du rang 1, qui attend celle du rang 0
→ 4 × 2 = 8 portes traversées, en série

C'est le défaut de cet additionneur : le temps de calcul croît LINÉAIREMENT avec le nombre de bits. Sur 64 bits, il serait inutilisable, et les processeurs emploient un additionneur à anticipation de retenue, qui calcule toutes les retenues en parallèle — plus de portes, moins de profondeur. Le compromis surface/vitesse apparaît dès le premier circuit qu'on construit.

La soustraction, gratuitement
entrée SUB (0 = addition, 1 = soustraction)

chaque bit de B passe par :  Bi XOR SUB
                               SUB=0 → Bi inchangé
                               SUB=1 → Bi inversé
retenue initiale Cin = SUB

SUB=1 : A + (non B) + 1 = A + (-B) = A - B

Quatre portes XOR et un fil : c'est tout ce que coûte la soustraction. C'est LA justification du complément à deux, et elle n'est vraiment convaincante qu'une fois le circuit sous les yeux. Un codage en signe et valeur absolue aurait exigé un comparateur, un soustracteur et une logique de signe.

Retenue et débordement, à ne pas confondre
Z = NON(S3 + S2 + S1 + S0)        résultat nul
V = C3 XOR C4                      débordement SIGNÉ

7 + 1 sur 4 bits signés :
0111 + 0001 = 1000 = -8
Cout = 0   (aucune retenue sortante)
V    = 1   (retenue entrante du dernier rang ≠ sortante)

Deux positifs qui donnent un négatif : le débordement est réel, mais la retenue sortante est nulle. C'est pourquoi il faut DEUX drapeaux — la retenue signale le débordement non signé, V le débordement signé. Le circuit calcule les deux à chaque opération, et c'est le programme qui choisit lequel regarder. Autrement dit, le processeur ne sait pas si vos nombres sont signés : vous seul le savez.

Le passage au séquentiel
bascule D : recopie D sur Q au FRONT MONTANT de l'horloge,
          et la conserve entre deux fronts

registre 4 bits = 4 bascules D partageant la même horloge

compteur : entrée du registre ← UAL(sortie du registre, 1, ADD)
         la sortie revient en entrée : une BOUCLE

Ce rebouclage est le basculement conceptuel du cours. Un circuit combinatoire n'a pas de passé : ses sorties ne dépendent que de ses entrées. Dès qu'une sortie revient en entrée à travers un élément cadencé, le circuit a un ÉTAT, donc une mémoire, donc du temps. Le compteur ordinal du chapitre 5 est exactement ce montage, en 32 ou 64 bits.

Ce que la suite en fait

Les briques de ce chapitre se retrouvent une à une dans le processeur du chapitre 5. Le registre devient le banc de registres et le compteur ordinal ; le décodeur devient la sélection d'une case mémoire et le décodage du code d'opération ; le multiplexeur choisit les entrées de l'unité arithmétique et logique, qui n'est elle-même qu'un additionneur entouré de quelques portes ; et l'horloge devient la fréquence affichée sur la fiche technique.

Le chemin critique, lui, ressortira deux fois : au chapitre 5 pour expliquer pourquoi un cycle dure ce qu'il dure, et au chapitre 8 pour expliquer ce que le pipeline gagne en le découpant.

À retenir

Flashcards · 4 cartes

Pourquoi dit-on que le NAND est universel, et quel intérêt pratique ?
Parce que toute fonction booléenne se construit avec des NAND seuls : NON a = NAND(a,a), le ET est un NAND suivi d'un inverseur, et le OU s'obtient par De Morgan. L'intérêt est technologique : en CMOS la porte naturelle est inverseuse, un NAND coûte 4 transistors contre 6 pour un ET. Les bibliothèques de cellules sont donc bâties sur NAND et NOR.
Quelles sont les deux sorties d'un additionneur complet, et quel lien avec le chapitre 3 ?
La somme s = a XOR b XOR r_entrante, et la retenue sortante r = ab + ar + br. Cette seconde expression est EXACTEMENT la fonction majorité simplifiée au tableau de Karnaugh : il y a une retenue dès que deux des trois entrées valent 1. Chaîner n additionneurs complets donne l'additionneur à propagation de retenue, dont le délai croît avec n.
Comment un même circuit additionne-t-il et soustrait-il ?
On place un XOR sur chaque bit du second opérande, commandé par un signal M, et on branche ce même M sur la retenue entrante du premier étage. M = 0 : b passe inchangé, le circuit additionne. M = 1 : b est inversé et on ajoute 1, ce qui donne −b en complément à deux, donc une soustraction. Coût : une porte XOR par bit.
D'où vient la mémoire dans un circuit séquentiel, et à quoi sert l'horloge sur front ?
De la TOPOLOGIE, pas d'un composant spécial : deux portes NOR croisées (bascule RS) conservent leur état quand leurs entrées retombent à 0, la boucle s'auto-entretenant. L'horloge sur front discipline ce rebouclage : l'état ne change qu'à l'instant du front montant, donc tout bascule ensemble et le circuit devient prévisible. La période d'horloge est fixée par le plus long chemin combinatoire, dit chemin critique.