Bascules et registres -- Comment les ordinateurs « se souviennent » des données

De la logique combinatoire à la logique séquentielle : comprendre le fonctionnement des bascules D et des registres


Analogie avec la vie : l’obturateur d’un appareil photo

Imaginez que vous avez un appareil photo dans la main. Avant que vous n’appuyiez sur l’obturateur, le monde extérieur change constamment : des piétons marchent, des feuilles oscillent, la lumière alterne entre clair et sombre.

Mais à l’instant où vous appuyez sur l’obturateur (front montant de l’horloge), la scène actuelle est « mémorisée » dans la photo.

Ensuite, peu importe comment le monde extérieur change, le contenu de la photo est à jamais figé à cet instant. C’est le comportement fondamental d’une bascule D : capturer et conserver des données sur le front montant du signal d’horloge.


Logique combinatoire vs logique séquentielle

Les portes ET, les portes OU, les portes NON et les autres circuits que nous avons étudiés dans les cours précédents appartiennent tous à lalogique combinatoirelogique combinatoire. Leurs sorties sont déterminées uniquement par les entrées actuelles : lorsque les entrées changent, les sorties changent immédiatement (en ignorant le délai de propagation).

Mais pour qu’un ordinateur « se souvienne » des données, il a besoin d’un circuit capable de maintenir sa sortie même après la disparition de l’entrée. C’est la logique séquentielle.Logique séquentielle。

Différence essentielle

La logique combinatoire est comme une lampe : quand on appuie sur l’interrupteur, elle s’allume ; quand on relâche, elle s’éteint ; la sortie dépend entièrement de l’entrée actuelle.

La logique séquentielle est comme un coffre-fort : vous y mettez quelque chose et vous le verrouillez (quand le front montant de l’horloge arrive), et même si vous partez ensuite (quand l’entrée disparaît), le contenu reste à l’intérieur.

Dimension de comparaison Logique combinatoire Logique séquentielle
Dépendance de sortie Dépend uniquement des entrées actuelles Dépend des entrées actuelles et de l'état précédent
Capacité de mémoire Aucune (sans état) Oui (peut mémoriser l'historique)
Circuit typique Porte ET, porte OU, porte NON, additionneur Bascule D, registre, compteur
Dépendance à l'horloge Ne dépend pas de l'horloge Repose sur le signal d'horloge pour synchroniser les mises à jour d'état
Boucle de rétroaction Pas de rétroaction (acyclique) Comporte des boucles de rétroaction pour maintenir l'état

Structure et comportement de la bascule D

Bascule DC'est l'unité logique séquentielle la plus élémentaire. Elle possède deux entrées et une sortie :

D (Donnée) : l'entrée de données, représentant la valeur à stocker (0 ou 1).

CLK (Horloge) : l'entrée d'horloge, contrôlant quand les données sont verrouillées.

Q : la sortie de données, délivrant la valeur actuellement stockée.

Comportement clé : la bascule D ne verrouille les données qu'aufront montantfront montant du signal d'horloge (l'instant où il passe de 0 à 1), verrouillant la valeur de D dans Q. À tous les autres moments, peu importe comment D change, Q reste inchangé.

C'est comme un appareil photo qui n'enregistre une scène qu'au moment où l'obturateur est déclenché ; à tout autre moment, peu importe comment la scène extérieure change, la photo n'est pas affectée.

Pourquoi une horloge est-elle nécessaire ?

Sans signal d'horloge, la sortie de la bascule D ne cesserait de changer avec l'entrée, ce qui en ferait un simple circuit logique combinatoire. Il ne serait pas question de « mémoire ».

Le signal d'horloge fournit unesynchronisation temporelle, permettant à toutes les bascules de mettre à jour leur état à un instant unifié. L'ensemble du système informatique coordonne son travail sous ce rythme.


Registre : plusieurs bascules en parallèle

Une seule bascule D ne peut stocker qu'1 bit de données. Pour stocker un octet (8 bits) ou un mot (32 bits), plusieurs bascules doivent être connectées en parallèle.

Connectez N bascules D en parallèle de sorte qu'elles,partagent le même signal d'horloge, formant unregistre à N bits。

lorsque le front montant de l'horloge arrive, elles verrouillent simultanément les valeurs sur leurs entrées D respectives, enregistrant ainsi les N bits de données complets en une seule fois.

Registres multi-étages et pipeline

À l'intérieur du CPU, les sorties des registres sont souvent connectées à l'étage suivant de logique combinatoire, qui à son tour se connecte à l'étage suivant de registres—formantRegistre-Logique combinatoire-Registreune structure de pipeline.

un pipeline dans lequel, à chaque cycle d'horloge, les données circulent d'un étage de registre à travers la logique combinatoire et sont stockées dans l'étage de registre suivant au prochain front montant. C'est la base du pipeline des CPU modernes.


Démonstration de code : simulation de bascules D et de registres en Python

Le code Python suivant simule le comportement d'une bascule D et d'un registre de 4 bits. Faites particulièrement attention à la logique de détection du front montant : les données ne sont capturées que lorsque clk est détecté passant de 0 à 1.

Exemple

class DFlipFlop:
    """
Bascule D : verrouille les données d'entrée sur le front montant de l'horloge

Règles de comportement :
- Lorsque l'horloge passe de 0 à 1 (front montant), l'entrée D est verrouillée sur la sortie Q.
- À d'autres instants (clk=0, ou clk=1 mais pas sur un front de transition), Q ne change pas
    """

    def __init__(self, name="DFF"):
        self.q = 0           # Sortie Q, initialement 0
        self.prev_clk = 0    # La valeur d'horloge à l'instant précédent, utilisée pour détecter le front montant
        self.name = name

    def update(self, d, clk):
        """
Mettre à jour l'état de la bascule

Paramètres :
d: Entrée de données (0 ou 1)
clk: Signal d'horloge (0 ou 1)

Retourne :
Valeur actuelle de la sortie Q

Détection de front montant : prev_clk == 0 et clk == 1
Ce n'est que lorsque cette condition est remplie que la valeur de d est verrouillée dans q
        """

        # === Détection de front montant ===
        if self.prev_clk == 0 and clk == 1:
            self.q = d  # Mémoriser la valeur de D en Q sur le front montant
        self.prev_clk = clk  # Enregistrer l'état d'horloge actuel pour le prochain cycle
        return self.q

    def reset(self):
        """Réinitialiser l'état de la bascule"""
        self.q = 0
        self.prev_clk = 0


class Register4Bit:
    """
Registre 4 bits : 4 bascules D en parallèle, partageant le même signal d'horloge

Schéma de structure :
D3 ──▶ [DFF3] ──▶ Q3 (bit de poids fort)
        D2 ──▶ [DFF2] ──▶ Q2
        D1 ──▶ [DFF1] ──▶ Q1
D0 ──▶ [DFF0] ──▶ Q0 (bit de poids faible)
↑↑↑↑ Partagent la même CLK

Lorsque le front montant de l'horloge arrive, les 4 bascules mémorisent simultanément leurs entrées D respectives.
    """

    def __init__(self):
        # Créez 4 bascules, avec bit[3] comme bit de poids fort et bit[0] comme bit de poids faible.
        self.flip_flops = [
            DFlipFlop("bit3"),
            DFlipFlop("bit2"),
            DFlipFlop("bit1"),
            DFlipFlop("bit0"),
        ]

    def update(self, data, clk):
        """
Mettre à jour le registre

Paramètres :
data : données à stocker (entier 0-15, les valeurs hors plage seront tronquées)
clk : signal d'horloge (0 ou 1)

Retourne :
Valeur actuellement stockée dans le registre (0-15)
        """

        data = data & 0b1111  # Vérifier que seuls 4 bits sont valides
        # Injecter chaque bit dans la bascule correspondante, bit de poids fort en premier
        for i in range(4):
            # Extraire chaque bit de poids fort à poids faible : bit3, bit2, bit1, bit0
            bit = (data >> (3 - i)) & 1
            self.flip_flops[i].update(bit, clk)
        return self.read()

    def read(self):
        """Lire la valeur actuellement stockée dans le registre (sans modifier l'état)"""
        value = 0
        for ff in self.flip_flops:
            value = (value << 1) | ff.q
        return value

    def reset(self):
        """Réinitialiser toutes les bascules"""
        for ff in self.flip_flops:
            ff.reset()


# ============================================================
# Démo de simulation : comportement du registre sur plusieurs cycles d'horloge
# ============================================================
if __name__ == "__main__":
    reg = Register4Bit()

    # Séquence de données de test : simuler l'écriture de différentes données à différents cycles d'horloge
    test_data = [5, 10, 15, 0, 7, 13, 3, 8, 1, 14]
    # 5=0101, 10=1010, 15=1111, 0=0000, 7=0111
    # 13=1101, 3=0011, 8=1000, 1=0001, 14=1110

    print("=" * 55)
    print(" exemple - démo de simulation de registre 4 bits")
    print(" Observation : les données sont verrouillées dans le registre uniquement sur le front montant de l'horloge")
    print("=" * 55)
    print(f"{'Période':<6} {'Horloge':<10} {'Données d'entrée D':<12} {'Valeur du registre Q':<12} {'Description'}")
    print("-" * 55)

    for cycle in range(10):
        data = test_data[cycle]

        # Étape 1 : Horloge basse (clk=0), les valeurs du registre ne doivent pas changer
        reg.update(data, 0)

        # Étape 2 : front montant de l'horloge (clk passe de 0→1), verrouiller data
        result = reg.update(data, 1)

        data_bin = f"{data:04b}"
        result_bin = f"{result:04b}"
        note = "← Verrouillage sur front montant" if result == data else "Statut inchangé"

        print(f"{cycle:<6} {'0→1':<10} {data}({data_bin}){'':<4} {result}({result_bin}){'':<4} {note}")

    print("-" * 55)
    print()

    # ============================================================
    # Démo supplémentaire : data n'est verrouillée que sur le front montant et conservée le reste du temps
    # ============================================================
    print("=" * 55)
    print(" Démo 2 : Lorsqu'on n'est pas sur le front montant, les changements de data ne sont pas verrouillés")
    print("=" * 55)

    reg2 = Register4Bit()
    # Écrire d'abord la valeur initiale 5
    reg2.update(5, 0)
    reg2.update(5, 1)
    print(fÉcrire 5 sur le front montant → valeur du registre : {reg2.read()})

    # clk reste à l'état haut, changer data en 10 — ne doit pas être verrouillé
    reg2.update(10, 1)
    print(fLorsque clk=1, changer data en 10 → valeur du registre : {reg2.read()} (devrait toujours être 5))

    # clk revient à l'état bas, puis écrire 10 sur le front montant
    reg2.update(10, 0)
    result = reg2.update(10, 1)
    print(fSur clk 0→1, écrire 10 → valeur du registre : {reg2.read()} (maintenant 10))

    print()
    print("=" * 55)
    print(" Démo terminée ! exemple - Comprendre les bascules et les registres")
    print("=" * 55)

Démo interactive : diagramme temporel de la bascule D

utiliser ci-dessousle stepped:true de Chart.jsL'option trace le diagramme temporel du signal d'horloge (signal carré) et du signal de données.Les lignes verticales rouges marquent chaque front montant de l'horloge (le moment où CLK passe de 0 à 1).Ces moments sont précisément les instants critiques où la bascule D verrouille les données.

Diagramme temporel de la bascule D — démonstration de verrouillage sur front montant

Horloge CLK (signal carré) Entrée de données D Sortie Q (valeur verrouillée)
Ligne rouge en pointillés = instant du front montant (la bascule D mémorise les données).
La sortie Q n'est mise à jour que sur le front montant et reste inchangée à tous les autres moments.
autres extensions